Erlang中每一个进程都有独立的堆内存,默认的大小是233个words(可配置),并以Fibonacci序列的顺序增加(233对应fib(11))。不过,当堆内存增大到必定程序时,增加速度减缓,好比内存大于fib(35)=14M的时候,堆内存开始不以Fibonacci序列增加(具体参见[$R15B_OTP_SRC/erts/emulator/beam/erl_gc.c --> erts_init_gc]里的说明)。通常状况下,进程所用到的数据都放在各自的堆内存中。spa
Erlang的GC机制跟其它语言(好比Java)相比,很重要的一点是,它的GC是以进程为单位进行的(通常状况下,GC搜索的根对象主要包括进程栈以及进程信箱中的对象)。Erlang系统中,GC进行时,会挂起整个系统(当前结点上的因此调度队列),也就是说它的GC也是“stop the world”。可是,就算一个系统中有大量进程,总共占用几个G的内存,它的GC的延迟也会很低,这是由于每一个进程可能只使用很小的内存(好比20K),在这么小的内存上进行GC所花费的时间很小,基本能够忽略不计。orm
在Erlang中能够经过spawn_opt来指定初始堆内存大小,若是这个数值足够大(须要诊断后肯定),那么就能够彻底避免GC。进程在销毁时,统一收回其所拥有的全部堆内存,而不须要进行GC,由于堆内存是每一个进程私有的。对象
Erlang中,堆内存被分红年轻代和年老代。进程在分配新数据时,会将数据放在年轻代中(分代的理论基础是大部分刚建立的对象会在不久的未来再也不使用)。只查看年轻代对象的GC称为minor GC,查看全部堆内存对象的GC称为major GC,所以minor GC比major GC更频繁,也更快。年轻代中的对象通过两到三次minor GC后,才会被拷贝到年老代。队列
Minor GC进程
年青代堆内存中存在一个标记位:高水位线(high water mark),比这个标记位地址小的对象称为较老的年轻代(older young generation),大于这个地址的称为较年轻的年轻代(younger young generation)。内存
Minor GC时,会分配一块新的堆内存,用于存放在能够在本次GC后能够生存下来的较年轻的年轻代。年轻代内存中被进程的根对象所引用的对象,若是它的地址小于高水位线,则会被拷贝到年老代堆内存,不然将其拷贝到新分配的堆内存中。而后根据新分配堆内存以及较老的年轻代堆内存中对象的引用,将全部活着的对象按原来的位置关系拷贝到新分配的堆内存或者年老代中。ci
Minor GC进行时,年老代堆内存不会被扫描,以加快GC速度。Minor GC完成后,会根据GC过程当中是否有较老的年轻代对象来决定高水位线的位置:若是存在,高水位线设置成it
新的年轻代堆内存的开始地址;若是不存在,则会设置成年轻代堆内存的堆顶地址。io
Major GC基础
Major GC时,年轻代堆内存和年老代堆内存中被根对象间接或直接引用到的对象都会被拷贝到新的堆内存中,高水位线会被设置成新的堆内存的堆顶地址。新的堆内存成为当前进程的年轻代堆,原来的老的堆内存(年轻代以及年老代)都会被释放。