2013-03-07 190 views
0

如果我做了以下內容:列表垃圾收集

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

看來,列表2是指在List1和Erlang:garbage_collect()不清晰的記憶。如何創建一個沒有引用的新列表並丟棄舊的?

+0

爲什麼你需要一個新的列表? – aronisstav 2013-03-07 09:08:55

+0

我有很多運行gen_servers與狀態列表,我想定期清理他們從過期的項目,以減少內存消耗。 – 2013-03-07 09:17:36

+0

您確定您沒有在某處保留對List1的某些引用,並且您實際上正在篩選出任何元素,以便List2小於List1? – RichardC 2013-03-07 09:45:48

回答

1

VM應該管理垃圾收集。如果您使用gen_server,或者如果您使用的是「自制」 server_loop(州),你應該總是相同的模式:

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() - > {合計,分配,最壞}。

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>不再是最壞的情況

0

如果您按照這種方式創建新列表,則新列表將包含第一個列表中的元素,一些元素將在這兩個列表之間共享。如果將第一個列表拋出,共享元素仍然可以從新列表中訪問,並且不會算作垃圾。

如何檢查第一個列表是否被垃圾收集?你在erlang控制檯中測試了嗎?控制檯存儲每個表達式的評估結果,這可能是您看不到列表垃圾收集的原因。

+0

不,我在真實應用程序上測試垃圾收集器的行爲,而不是在控制檯中。我用htop來監視內存消耗。 有沒有一種方法可以創建沒有將在兩個列表之間共享的元素的列表? – 2013-03-07 09:31:41

+0

我不明白你爲什麼需要這個。您將擁有使用相同內存的相同元素。 唯一有用的情況是如果你有一個巨大的二進制文件,並且你匹配它的一小部分。在這種情況下,新的子二進制文件將只是指向具有偏移和長度參數的主二進制文件的指針,因此您的二進制文件也不會被垃圾收集。爲此,你有'binary:copy/1'。 – 2013-03-07 10:13:25

+0

如果L1 = [A1,A2,A3,A4,A5]和L2 = [A1],那麼我希望元素A2-A5已從內存中移除。 – 2013-03-07 11:32:07

1

在使用垃圾收集的任何語言中,只需要在「垃圾收集」之前「丟失」所有對某段數據的引用。只需從生成原始列表的函數返回,而不將其存儲在任何其他「持久性」位置(例如過程字典)中,就應該允許回收內存。

+1

@P_A當沒有對它們的引用時,'List1'中的元素將被垃圾回收器自動刪除。垃圾收集的整個過程不必明確地擔心刪除對象,不必擔心它們是否存在以及誰將刪除它們。在Erlang中,就像大多數帶有垃圾收集器的語言一樣,沒有明確的'free'。明確的「免費」總是充滿危險。在這種情況下,系統確實比你知道的要好。 – rvirding 2013-03-08 00:23:42