2009-12-23 74 views
1

我经历利尼和汤普森的“Erlang编程”(O'Reilly出版),我做了一个解决方案,以4-2,但玩了后,有两个问题:这个erlang代码为什么会吃这么多的内存?

  1. 我每次运行去/ 3,Windows中的“werl.exe”咀嚼X数量的RAM。随后的每次通话都会收到相同的金额,而且从未回收。

  2. 如果我去跑(消息,10000,10)它吃了1.4GB RAM和崩溃从我

我认为,在我的第二个情况下,二郎应该处理这个没问题一直在阅读,所以我的猜测是,我不知何故引入了内存泄漏?我阅读了关于内存泄漏和尾递归的部分,并没有看到我做错了什么。

在此先感谢。

 
-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) -> 
    [].
+0

这并不真正回答问题#2。但是,当你注册一个进程时,你基本上正在创建和设置一个全局变量,这就是内存泄漏。 – Omnifarious 2009-12-23 22:52:18

+0

@Omnifarious:只注册一个进程。 – Zed 2009-12-23 22:58:11

+0

是的,但是这个过程可能通过引用保留所有其他过程。无论如何,看起来有人真的比我更好地回答了这个问题,虽然我是对的,但我的想法并不是全部真相,这就是为什么我没有把它作为答案。 :-)我自己是Erlang的新手。 – Omnifarious 2009-12-24 01:54:22

回答

1

ProcList包含所有派生进程的Pid列表。该列表由所有进程接收。对于你的例子,这意味着每回合10.000 x 10.000 Pids。这是相当多的记忆!

除非垃圾回收可以设置为在收到列表后立即摆脱列表,否则这将不起作用...尝试在waitMessage()尾部呼叫之前尝试呼叫erlang:garbage_collect()

+0

哦,这个列表在每一步都收缩了,所以它每回合只有10.000 x 5.000 Pid :) – Zed 2009-12-23 22:53:54

+0

Ahhhhhh,当然!我来自Java,所以我忘了每次都复制这些darn列表。 – ckovacs 2009-12-23 23:08:50

+0

我试着按照你的建议使用garbage_collect(),但内存使用率仍然随着每次调用/ 3而上升。例如,go(hello,5000,5)每次致电我的werl.exe进程增加5mb – ckovacs 2009-12-23 23:27:35

0

我不能没有看到“崩溃转储”完全肯定,但我怀疑,下面可能会引起一些悲痛:

[spawn(chap9q1,waitMessage,[]) | buildList(N - 1)];

,因为你的源代码列表显示

-module(processRing).该模块被命名为与您试图获取的spawn(模块名称是第一个参数)不同的内容。换句话说:您正在尝试构建大量进程,但其中每一个进程都会失败,我怀疑“垃圾回收”需要一些时间来清理。

+0

我敢打赌,崩溃转储将被截断,所以它不会产生可用的信息。至少我从来没有见过1.5 GB的崩溃转储:o) – Zed 2009-12-23 22:52:48

+1

我的错误!为了清晰起见,我在发布到论坛之前更改了模块的名称。它不能解决问题,但眼睛好!它与每次复制巨大的列表有关 – ckovacs 2009-12-23 23:14:24

相关问题