如果我执行以下操作:
List2 = [V || V <- List1, ...]
似乎 List2 指的是 List1 和 erlang:garbage_collect() 不清除内存。如何创建没有引用的新列表并丢弃旧列表?
如果我执行以下操作:
List2 = [V || V <- List1, ...]
似乎 List2 指的是 List1 和 erlang:garbage_collect() 不清除内存。如何创建没有引用的新列表并丢弃旧列表?
在任何带有垃圾收集的语言中,您只需要“丢失”对一条数据的所有引用,然后它就可以被垃圾收集。简单地从生成原始列表的函数返回,而不是将其存储在任何其他“持久”位置(例如进程字典),应该允许回收内存。
虚拟机应该管理垃圾收集。如果您使用 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> 不再是最坏的情况
如果您像这样创建新列表,新列表将包含第一个列表中的元素,一些元素将在两个列表之间共享。如果你把第一个列表扔掉,共享元素仍然可以从新列表中访问,并且不会被视为垃圾。
你如何检查第一个列表是否被垃圾收集?您是否在 erlang 控制台中对此进行了测试?控制台存储每个表达式的评估结果,这可能是您看不到垃圾收集列表的原因。