views:

243

answers:

2

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:

  1. 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.

  2. 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) ->
    [].
A: 

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 get spawn 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.

jldupont
I bet the crash dump will be truncated, so it would yield no usable information. At least I've never seen crash dumps of 1.5 GB :o)
Zed
My mistake! I changed the name of the module before posting to the forum for clarity. It doesn't solve the problem, but good eye! It has to do with copying the gigantic lists every time
ckovacs
+1  A: 

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 the waitMessage() tail calls.

Zed
Oh, the list is shrunk at each step, so it's just 10.000 x 5.000 Pids per turn :)
Zed
Ahhhhhh, of course! I'm coming from Java so I forget that these darn lists are copied every single time.
ckovacs
I tried using the garbage_collect() as you suggested, but memory usage still climbs with every call to go/3. Eg go(hello,5000,5) grows my werl.exe process by 5mb per call
ckovacs
You never kill your processes. Each call to go will leave 5000 (well, 4999) processes hanging around... The default heap size for a process is 233 words so if you use a 64-bit system that should add up to the missing 5MB.
Zed
Thanks again, I send a stop message to the processes now and it's all good. Yes, it's a 64 bit system. Thanks again, this is all starting to make a lot more sense now. I've just about optimized my solution so it doesn't pass the lists around either.
ckovacs