Erlang垃圾回收特点:
1. 以进程为单位进行垃圾回收,GC时会导致进程挂起
2. ETS和原子不参与垃圾回收
Erlang垃圾回收采用分代复制回收的方式,分代回收是基于统计学原理,多数内存块的生存周期都比较短,最近创建的对象更容易变冷(不再被使用)。分代垃圾回收将内存对象分为新生和老年代两个部分,进程在分配新数据时,会将数据放在年轻代中。
Erlang的GC可以分成两种:部分垃圾回收与全量垃圾回收。部分垃圾回收只对年轻一代的对象进行垃圾回收,其频率会更频繁,这样可以减少对常驻内存对象的GC次数。在进行了一定次数的部分垃圾回收之后,或者部分垃圾回收没能释放足够的内存的时候就会促发全量垃圾回收。
年轻代中的对象经过2~3次的部分垃圾回收之后才会被拷贝至老年代。
部分垃圾回收
年青代堆内存中存在一个标记位:高水位线(high water mark),比这个标记位地址小的对象称为较老的年轻代(olderyoung generation),大于这个地址的称为较年轻的年轻代(younger younggeneration)。
MinorGC时,会分配一块新的堆内存,用于存放在可以在本次GC后可以生存下来的较年轻的年轻代。年轻代内存中被进程的根对象所引用的对象,如果它的地址小于高水位线,则会被拷贝到年老代堆内存,否则将其拷贝到新分配的堆内存中。然后根据新分配堆内存以及较老的年轻代堆内存中对象的引用,将所有活着的对象按原来的位置关系拷贝到新分配的堆内存或者年老代中。
Minor GC进行时,年老代堆内存不会被扫描,以加快GC速度。Minor GC完成后,会根据GC过程中是否有较老的年轻代对象来决定高水位线的位置:如果存在,高水位线设置成新的年轻代堆内存的开始地址;如果不存在,则会设置成年轻代堆内存的堆顶地址。
全量垃圾回收
Major GC时,年轻代堆内存和年老代堆内存中被根对象间接或直接引用到的对象都会被拷贝到新的堆内存中,高水位线会被设置成新的堆内存的堆顶地址。新的堆内存成为当前进程的年轻代堆,原来的老的堆内存(年轻代以及年老代)都会被释放。
查看进程垃圾回收状态
通过erlang:process_info(Pid)的进程状态查看该进程垃圾回收的相关信息。
min_bin_vheap_size:进程最小虚拟二进堆大小
min_heap_size:进程最小堆大小
fullsweep_after:执行多少次部分垃圾回收之后进行一次全量垃圾回收
minor_gcs:当前已执行的部分垃圾回收次数
可使用garbage:collect(),garbage:collect(Pid)手动进行垃圾回收。
使用garbage:collect()一键回收进程垃圾,但并不能完全将所有进程的垃圾全部回收。
参考资料: