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
相关文章
相关标签/搜索