Erlang進程堆垃圾回收機制

做者:http://blog.csdn.net/mycwq html

每一個Erlang進程建立以後都會有本身的PCB,棧,私有堆。erlang不知道他建立的進程會用到哪一種場合下,因此一開始分配的內存比較小。若是分配的空間不夠了,erlang gc會動態調整堆大小以知足需求,若是分配的空間大了,就會收縮堆,回收內存。 ide

erlang進程堆的gc是分代gc,分代gc的想法基於統計學:大部分數據的生存週期都比較短,最新的數據更容易再也不被使用。這裏erlang使 用young heap 和old heap來區分數據,young heap放新數據,old heap放舊數據,也就是gc後存活的數據。 函數

erlang進程堆gc有兩個主要過程:淺掃描和深掃描 ui

淺掃描(minor collection) spa

淺掃描是當young heap空間不足時,erlang會對young heap作一次掃描,把有用的數據複製到新申請的young heap空間,發現已經掃描過1次以上的數據放入old heap,而後刪掉原來的young heap .net

在young heap中,erlang使用了高水位線來區分標記一次以上的數據和未標記的數據,那麼young heap移入old heap的就是超太高水位線的數據 orm

深掃描(major collection) htm

深掃描是通常當old heap空間不足時觸發,erlang會對young heap和old heap作掃描,把有用的數據放入新申請的young heap,刪掉原來的heap blog

深掃描的觸發條件還有手動執行gc,和gc次數超過fullsweep_after的參數限定 生命週期



控制垃圾回收

以遊戲網關進程爲例,網關進程一般有大量消息,而大部分消息都只是在網關這裏作轉發,生命週期很短,因此網關進程能夠設定較大的初始內存,較快的內存回收。

spawn_opt(Fun, [{min_heap_size, 5000},{min_bin_vheap_size, 100000},{fullsweep_after, 500}])

先看下參數默認值:
1> erlang:system_info(min_heap_size).
{min_heap_size,233}
2> erlang:system_info(min_bin_vheap_size).
{min_bin_vheap_size,46368}
3> erlang:system_info(fullsweep_after).
{fullsweep_after,65535}

min_heap_size是進程最小堆大小

這個參數兩個地方會用到,第一處是erlang初始化進程堆大小,第二處是gc後堆收縮後維持的最小值,min_bin_vheap_size是進 程最小虛擬二進制堆大小,這兩個參數都是以word爲單位。初始化足夠大的初始內存,能夠減小輕度gc的次數,減小反覆申請和回收內存的開銷

fullsweep_after控制深掃描的頻率

這個參數肯定多少次gc後執行一次深度gc,默認值爲65536,有點大了

因此,上面3個參數配合起來的意義就是,進程初始化分配足夠大的內存,減小反覆申請內存的開銷,當申請的內存不夠用,gc會從新申請內存,累計達到500次就作一次gc


手動執行垃圾回收

上面提到了利用fullsweep_after來控制gc的狀況,下面再介紹手動gc的狀況:
在rabbitMQ看到這段代碼,能夠在項目中按期執行這個函數:
gc() ->
    [erlang:garbage_collect(P) || P <- erlang:processes(),
                           {status, waiting} == erlang:process_info(P, status)],
    erlang:garbage_collect(),
    ok.

固然,你還能夠加入一些判斷,好比指定佔內存過50M的進程執行gc

erlang進程佔用多少內存

用下面這個方法檢查erlang進程佔用的內存,你能夠換別的參數再試試
Fun = fun()-> receive after infinity -> ok end end.
erlang:process_info(erlang:spawn(Fun), memory).


erlang垃圾回收的反作用

前面講到erlang進程堆的gc是分代gc的,這個只是全局層面的,在底層erlang仍是走了標記清除的路子。標記清除這種gc方式是按期執行 的,首先gc不夠及時,其次,在gc執行期間開銷比較大,會引發中斷。不過每一個erlang進程的堆區域是獨立的,gc能夠獨立進行,加上它內存區域比較 小,還有erlang的變量是單次賦值,無需屢次追蹤,所以,erlang進程gc的延遲不會引發全局的中斷

erlang文檔 參考
GC in Erlang works independently on each Erlang process, i.e. each Erlang process has its own heap, and that heap is GCed independently of other processes' heaps.
The current default GC is a "stop the world" generational mark-sweep collector. On Erlang systems running with multiple threads (the default on systems with more than one core), GC stops work on the Erlang process being GCed, but other Erlang processes on other OS threads within the same VM continue to run. The time the process spends stopped is normally short because the size of one process' heap is normally relatively small; much smaller than the combined size of all processes heaps.

結束語

這裏講了erlang進程堆的gc,另外erlang還有其餘gc機制,好比,二進制共享堆和進程外堆碎片是引用計數gc,這裏先不作討論,有時間我會在下篇作討論,有興趣能夠看這裏瞭解一下。


參考:

http://blog.csdn.net/mycwq/article/details/26613275

http://www.cnblogs.com/me-sa/archive/2011/11/13/erlang0014.html
相關文章
相關標籤/搜索