Память течет

24 views
Skip to first unread message

Denek

unread,
Nov 19, 2009, 3:34:28 PM11/19/09
to Erlang в России
-module(chat).
-export([start/1]).

-define(TCP_OPTIONS, [list, {packet, 0}, {active, false}, {reuseaddr,
true}]).

start(Port) ->
Pid = spawn(fun() -> manage_clients([]) end),
register(client_manager, Pid),
{ok, LSocket} = gen_tcp:listen(Port, ?TCP_OPTIONS),
do_accept(LSocket).

do_accept(LSocket) ->
{ok, Socket} = gen_tcp:accept(LSocket),
spawn(fun() -> handle_client(Socket) end),
client_manager ! {connect, Socket},
do_accept(LSocket).

handle_client(Socket) ->
case gen_tcp:recv(Socket, 0) of
{ok, Data} ->
Policy = string:str(Data, "<policy-file-request/>"),
case Policy of
1 ->
io:fwrite("Policy request~n"),
{ok, Cross} = file:read_file('crossdomain.xml'),
CrossNew = lists:append(binary_to_list(Cross), [0]),
gen_tcp:send(Socket, CrossNew);
0 ->
%% io:fwrite("~s~n", [Data]),
client_manager ! {data, Data}
end,
handle_client(Socket);
{error, closed} ->
client_manager ! {disconnect, Socket}
end.

manage_clients(Sockets) ->
receive
{connect, Socket} ->
io:fwrite("Socket connected: ~w~n", [Socket]),
NewSockets = [Socket | Sockets];
{disconnect, Socket} ->
io:fwrite("Socket disconnected: ~w~n", [Socket]),
NewSockets = lists:delete(Socket, Sockets);
{data, Data} ->
send_data(Sockets, Data),
NewSockets = Sockets
end,
manage_clients(NewSockets).

send_data(Sockets, Data) ->
SendData = fun(Socket) ->
gen_tcp:send(Socket, Data)
end,
lists:foreach(SendData, Sockets).

Вот и я начал свой путь в мир Erlang'a, и сразу столкнулся с
непоняткой:

Вот есть такой исходный код echo сервера, при 100 активных соединениях
и активном флуде каждым клиентом, современем (в процессе работы сразу)
начинает течь память, может программа неправильно построена

Max Lapshin

unread,
Nov 19, 2009, 3:41:14 PM11/19/09
to erlang-...@googlegroups.com
Что бы понять, что именно течет, воспользуйтесь processes() и process_info(..).

У вас есть типичнейший пример места с утечкой: это неполный receive.
Если кто-то будет слать сообщения
client_manager-у, которые он не может обработать, его mailbox будет заполняться.

Есть ещё проблема, поскольку вы не используете ни OTP, ни spawn_link,
то падающие клиентские процессы
не закрывают сокеты.

Denis Chernienko

unread,
Nov 19, 2009, 3:49:42 PM11/19/09
to erlang-...@googlegroups.com
Спасибо огромное, а есть сборник типичных ошибок начинающих, чтобы глупыми проблемами не засорять коммунити?

Иван

unread,
Nov 19, 2009, 5:54:37 PM11/19/09
to Erlang в России
Чтобы было проще постигать Erlang:

lists:reverse(lists:sort([{erlang:process_info(P, message_queue_len),
P} || P <- processes()])).

Ну и потом с помощью
erlang:process_info(list_to_pid("<0.0.0>")).
можно посмотреть что это за процесс :)

Alexey Kishkin

unread,
Nov 19, 2009, 6:18:33 PM11/19/09
to erlang-...@googlegroups.com
Иван пишет:

> Чтобы было проще постигать Erlang:
>
> lists:reverse(lists:sort([{erlang:process_info(P, message_queue_len),
> P} || P <- processes()])).
>
>

i(). пишет в последней колонке длину очереди процессов.

Иван

unread,
Nov 19, 2009, 7:15:23 PM11/19/09
to Erlang в России
Да, но если процессов больше сотни, пользоваться i() неудобно. А тут
сразу вся картина на ладони :)

Max Lapshin

unread,
Nov 20, 2009, 12:08:25 AM11/20/09
to erlang-...@googlegroups.com
etop:start([{output, text}]).

Denis Chernienko

unread,
Nov 26, 2009, 3:46:39 PM11/26/09
to erlang-...@googlegroups.com
вот к чему привело расследование =), у меня скорость интернета дома 2 Мбит/c. когда начинался флуд - он получался потоковым + эхо сервер на 10 подключений, то есть на одно сообщение мне нужно было ответить 10ю сообщениями. Но траффик нашим провайдером шейпится как один на исходящий + входящий. То при потоковом флуде входящая скорость 1,5 Мбит/с, а для исходящей остаётся 500 Кбит/с. Но для текущего echo сервера это мало )), вот и накапливаются мессаги.

При флуде со слипом в 1 секунду, всё нормально, то есть выходит наоборот.

как обрабатывать такие вещи?

Max Lapshin

unread,
Nov 26, 2009, 3:54:57 PM11/26/09
to erlang-...@googlegroups.com
Как вариант, можно {active, once}, тогда наполнятся все TCP буферы и
посылающая сторона не сможет писать.
Это самое логичное поведение, как мне кажется.

Denis Chernienko

unread,
Nov 27, 2009, 2:49:02 AM11/27/09
to erlang-...@googlegroups.com
проверил не помогает тут как раз буфер на отправку наполняется =), по ходу единственный выход настраивать траффик шейпер.

Denis Chernienko

unread,
Nov 27, 2009, 3:04:36 AM11/27/09
to erlang-...@googlegroups.com
или ограничивать буфер на отправку =)
Reply all
Reply to author
Forward
0 new messages