为什么这段 erlang 代码会占用这么多内存?
我正在阅读 Cesarini 和 Thompson 的“Erlang 编程”(O'Reilly),并提出了 4-2 的解决方案,但在尝试之后出现了两个问题:
每次我运行 go/3 时,“werl Windows 中的“.exe”会占用 X 数量的 RAM。随后的每个调用都会占用相同的数量,并且永远不会被回收。
如果我运行 go(Message,10000,10) 它会占用 1.4GB RAM 并崩溃
我认为在我的第二种情况,从我读到的内容来看,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) -> [].
I'm going through Cesarini and Thompson's "Erlang Programming" (O'Reilly) and I made a solution to 4-2 but after playing around with it there are two problems:
Every time I run go/3, "werl.exe" in windows chews up X amount of RAM. Every subsequent call takes up the same amount and it's never reclaimed.
If I run go(Message,10000,10) it eats up 1.4GB RAM and crashes
I thought that in my second case, Erlang should handle this no problem from what I've been reading, so my guess is that I've somehow introduced a memory leak? I read the sections on memory leaks and tail recursion and don't see what I'm doing wrong.
Thanks in advance.
-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) -> [].
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
ProcList 包含所有生成进程的 Pids 列表。所有进程都会收到此列表。对于您的示例,这意味着每轮 10.000 x 10.000 Pids。这可是相当大的内存啊!
除非垃圾收集可以设置为在收到列表后立即删除列表,否则这是行不通的...尝试在
waitMessage() 之前调用
尾部调用。erlang:garbage_collect()
ProcList contains the list of Pids of all spawned processes. This list is received by all processes. For your example this means 10.000 x 10.000 Pids for each turn. That's quite a lot of memory!
Unless garbage collection can be set to get rid of the list as soon as the list is received, this won't work... try calling
erlang:garbage_collect()
before thewaitMessage()
tail calls.如果没有看到“崩溃转储”,我无法完全确定,但我怀疑以下内容可能会造成一些悲伤:
[spawn(chap9q1,waitMessage,[]) | buildList(N - 1)];
因为您的源列表显示
-module(processRing).
该模块的命名与您尝试获取的spawn
不同code> 进行操作(模块名称是第一个参数)。换句话说:您正在尝试构建大量进程,但每个进程都会失败,我怀疑“垃圾收集”将需要一些时间来清理。
I can't be entirely sure without seeing the "crash dump" but I suspect that the following might be causing some grief:
[spawn(chap9q1,waitMessage,[]) | buildList(N - 1)];
because your source listing shows that
-module(processRing).
the module is named something different from what you are trying to getspawn
to act on (module name is the first parameter).In other words: you are trying to build a huge number of processes but every one of them will be failing and I suspect that the "garbage collection" will take some time to clean-up.