私が次のことをした場合:
List2 = [V || V <- List1, ...]
List2 が List1 を参照していて、erlang:garbage_collect() がメモリをクリアしていないようです。参照なしで新しいリストを作成し、古いリストを破棄するにはどうすればよいですか?
私が次のことをした場合:
List2 = [V || V <- List1, ...]
List2 が List1 を参照していて、erlang:garbage_collect() がメモリをクリアしていないようです。参照なしで新しいリストを作成し、古いリストを破棄するにはどうすればよいですか?
ガベージ コレクションを使用する言語では、ガベージ コレクションを実行する前に、データへの参照をすべて「失う」必要があります。元のリストを生成する関数から単に戻るだけで、それを他の「永続的な」場所 (プロセス辞書など) に格納しないで、メモリを再利用できるはずです。
VMはガベージコレクションを管理することになっています。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 コンソールでこれをテストしますか? コンソールには、リストのガベージ コレクションが表示されない原因となる可能性がある各式の評価結果が格納されます。