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位系统。再次感谢你,现在一切都变得更有意义了。我刚刚对我的解决方案进行了优化,这样它也不会传递列表。