Memory leaks 为什么这个erlang代码占用了这么多内存?
Memory leaks 为什么这个erlang代码占用了这么多内存?,memory-leaks,erlang,Memory Leaks,Erlang,我正在学习塞萨里尼和汤普森的“Erlang编程”(O'Reilly),我提出了4-2的解决方案,但在使用它之后,有两个问题:
每次我运行go/3时,windows中的“werl.exe”都会消耗X个内存量。随后的每一次通话都会占用相同的金额,而且永远不会收回
如果我运行go(Message,10000,10),它会占用1.4GB内存并崩溃
我认为在我的第二个例子中,Erlang应该处理这个问题,从我所阅读的内容来看,没有问题,所以我猜我不知何故引入了内存泄漏?我阅读了关于内存泄漏和尾部递归的部分
我正在学习塞萨里尼和汤普森的“Erlang编程”(O'Reilly),我提出了4-2的解决方案,但在使用它之后,有两个问题:
每次我运行go/3时,windows中的“werl.exe”都会消耗X个内存量。随后的每一次通话都会占用相同的金额,而且永远不会收回
如果我运行go(Message,10000,10),它会占用1.4GB内存并崩溃
我认为在我的第二个例子中,Erlang应该处理这个问题,从我所阅读的内容来看,没有问题,所以我猜我不知何故引入了内存泄漏?我阅读了关于内存泄漏和尾部递归的部分,但没有看到我做错了什么
提前谢谢
-module(processRing).
-export([waitMessage/0,go/3]).
% Spawn M processes and pass Message around to each process N times
go(Message,M,N) ->
ProcList = buildList(M),
[H | T ] = ProcList,
register(firstProc,H),
H ! {self(), T, ProcList, Message, N}.
waitMessage() ->
receive
{_, _, _, _, 0} ->
io:format("end!", []);
{From, [H|T], AllProcs, Message, N} ->
%io:format("~w:~w from:~w~n n=~w",[self(),Message,From,N]),
H ! {self(), T, AllProcs, Message, N},
waitMessage();
{From, [], AllProcs, Message, N} ->
io:format("~w:~w (Last in list) from:~w n=~w~n",[self(),Message,From,N]),
firstProc ! {self(), AllProcs, AllProcs, Message, N - 1},
waitMessage();
Other ->
io:format("other:~w~n",[Other])
end.
buildList(N) when N > 0 ->
[spawn(processRing,waitMessage,[]) | buildList(N - 1)];
buildList(0) ->
[].
-模块(处理环)。
-导出([waitMessage/0,go/3])。
%生成M个进程并将消息传递给每个进程N次
go(消息,M,N)->
ProcList=buildList(M),
[H | T]=ProcList,
寄存器(firstProc,H),
H{self(),T,ProcList,Message,N}。
waitMessage()->
接收
{_, _, _, _, 0} ->
io:格式(“结束!”,[]);
{From[H|T],AllProcs,Message,N}->
%io:format(“~w:~w from:~w~n=~w”,[self(),Message,from,n]),
H{self(),T,AllProcs,Message,N},
waitMessage();
{From,[],AllProcs,Message,N}->
io:format(~w:~w(列表中最后一个)from:~w n=~w~n),[self(),Message,from,n]),
第一步!{self(),AllProcs,AllProcs,Message,N-1},
waitMessage();
其他->
io:格式(“其他:~w~n”,[other])
结束。
当N>0->
[spawn(processRing,waitMessage,[])| buildList(N-1)];
构建列表(0)->
[]。如果没有看到“崩溃转储”,我无法完全确定,但我怀疑以下可能会引起一些悲伤:
[spawn(第9q1章,waitMessage,[])| buildList(N-1)]代码>
因为你的源代码列表显示
-module(processRing)。
模块的名称与您试图让spawn
执行操作的名称不同(模块名称是第一个参数)
换句话说:您正试图构建大量进程,但每一个进程都将失败,我怀疑“垃圾收集”将需要一些时间来清理。ProcList包含所有派生进程的PID列表。所有进程都会收到此列表。例如,这意味着每转10.000 x 10.000个PID。那是相当多的记忆
除非垃圾收集可以设置为在收到列表后立即清除列表,否则这将不起作用。。。尝试在waitMessage()
尾部调用之前调用erlang:garbage\u collect()
。这并不能真正解决问题2。但是,当您注册一个进程时,您基本上是在创建和设置一个全局变量,这就是内存泄漏。@Omnifarious:只注册了一个进程。是的,但该进程可能通过引用保留所有其他进程。不管怎么说,似乎有人对这个问题的回答确实比我好,虽然我是对的,但我的想法并不是全部的真相,这就是为什么我没有把它作为答案的原因。:-)我自己也是个二郎新手。@Omnifarious:我明白你的意思。在Erlang中,注册仅意味着将一个条目放入包含名称和进程id的“全局”查找表中。它与进程的生命周期和堆无关。另外,一个进程保持另一个进程的pid并不意味着什么。不要用Java或C#之类的东西来思考:)我打赌崩溃转储将被截断,因此不会产生任何可用信息。至少我从未见过1.5GB的崩溃转储:o)我的错误!为了清晰起见,我在发布到论坛之前更改了模块的名称。这并不能解决问题,但是眼睛好!它必须与每次复制巨大的列表有关哦,列表在每一步都会缩小,所以每一圈只有10.000 x 5.000个PID:)啊,当然!我来自Java,所以我忘了这些该死的列表每次都会被复制。我试着按照你的建议使用垃圾收集()方法,但每次调用go/3时内存使用率仍然会上升。例如go(您好,5000,5)将我的werl.exe进程每调用一次增加5mb您永远不会停止进程。每次调用go都会留下5000个(4999个)进程。。。一个进程的默认堆大小是233个字,因此如果使用64位系统,加起来应该会丢失5MB。再次感谢,我现在向进程发送了一条停止消息,一切正常。是的,这是一个64位系统。再次感谢你,现在一切都变得更有意义了。我刚刚对我的解决方案进行了优化,这样它也不会传递列表。