1

如果我执行以下操作:

List2 = [V || V <- List1, ...]

似乎 List2 指的是 List1 和 erlang:garbage_collect() 不清除内存。如何创建没有引用的新列表并丢弃旧列表?

4

3 回答 3

2

在任何带有垃圾收集的语言中,您只需要“丢失”对一条数据的所有引用,然后它就可以被垃圾收集。简单地从生成原始列表的函数返回,而不是将其存储在任何其他“持久”位置(例如进程字典),应该允许回收内存。

于 2013-03-07T12:40:00.333 回答
1

虚拟机应该管理垃圾收集。如果您使用 gen_server,或者如果您使用“自制” server_loop(State),则应该始终使用相同的模式:

server_loop(State) ->
   A = somefunc(State),
   B = receive
          mesg1 -> func1(...);
          ...
       after Timeout ->
          func2(...)
       end,
   NewState = func3(...),
   server_loop(NewState).

只要一个进程还活着,执行这个循环,VM就会分配和管理内存区域来存储所有需要的信息(变量,消息队列......+一些余量)据我所知,有一些空闲内存分配给进程,并且如果 VM 在释放内存后没有尝试很快恢复内存,但是如果您强制进行垃圾收集,使用 erlang:garbage_collect(Pid) 您可以验证内存是否空闲 - 请参见下面的示例。

startloop() -> spawn(?MODULE,loop,[{lists:seq(1,1000),infinity}]).

loop(endloop) -> ok;
loop({S,T}) ->
    NewState = receive
        biglist -> {lists:seq(1,5000000),T};
        {timeout,V} -> {S,V};
        sizelist -> io:format("Size of the list = ~p~n",[length(S)]),
                            {S,T};
        endloop -> endloop
    after T ->
        L = length(S) div 2,
        {lists:seq(1,L),T}
    end,
    loop(NewState).
    %% Here, NewState is a copy of State or a totally new data, depending on the
    %% received message. In general, for performance consideration it can be 
    %% interesting to take care of the function used to avoid big copies, 
    %% and allow the compiler optimize the beam code 
    %% [H|Q] rather than Q ++ [H] to add a term to a list for example

和VM中的结果:

2> P = lattice:startloop().
<0.57.0>
...
6> application:start(sasl).  
....
ok
7> application:start(os_mon).
...
ok
...
11> P ! biglist.
biglist
...

% get_memory_data() -> {Total,Allocated,Worst}。

14> memsup:get_memory_data().
{8109199360,5346488320,{<0.57.0>,80244336}}
...
23> P ! {timeout,1000}.             
{timeout,1000}
24> memsup:get_memory_data().
{8109199360,5367361536,{<0.57.0>,80244336}}

最坏的情况是循环过程:{<0.57.0>,80244336}

...
28> P ! sizelist.            
Size of the list = 0
sizelist
...
31> P ! {timeout,infinity}.
{timeout,infinity}
32> P ! biglist.                    
biglist
33> P ! sizelist.          
Size of the list = 5000000
sizelist
...
36> P ! {timeout,1000}.      
{timeout,1000}
37> memsup:get_memory_data().
{8109199360,5314289664,{<0.57.0>,10770968}}

%% 注意上一行中的垃圾收集:{<0.57.0>,10770968}

38> P ! sizelist.            
sizelist
Size of the list = 156250
39> memsup:get_memory_data().
{8109199360,5314289664,{<0.57.0>,10770968}}
...
46> P ! sizelist.            
Size of the list = 0
sizelist
47> memsup:get_memory_data().
{8109199360,5281882112,{<0.57.0>,10770968}}
...
50> erlang:garbage_collect(P).
true
51> memsup:get_memory_data(). 
{8109199360,5298778112,{<0.51.0>,688728}}

%% 在 GC 之后,进程 <0.57.0> 不再是最坏的情况

于 2013-03-07T22:02:52.753 回答
0

如果您像这样创建新列表,新列表将包含第一个列表中的元素,一些元素将在两个列表之间共享。如果你把第一个列表扔掉,共享元素仍然可以从新列表中访问,并且不会被视为垃圾。

你如何检查第一个列表是否被垃圾收集?您是否在 erlang 控制台中对此进行了测试?控制台存储每个表达式的评估结果,这可能是您看不到垃圾收集列表的原因。

于 2013-03-07T09:24:38.477 回答