分代收集理论(Generation Collection)
弱分代假说(Weak Generation Collection)强分代假说(Strong Generation Collection) 建立在分代收集理论上的收集算法
标记-清除算法(Mark-Sweep)标记-复制算法(Mark-Copying)标记-整理算法(Mark-Compac)
分代收集理论(Generation Collection)GC收集器应该将Java堆划分为不同的区域,然后对象依据其年龄(经过GC收集的次数),存储到不同的内存区域。
该理论建立在两个假说上:弱分代假说和强分代假说。
弱分代假说(Weak Generation Collection)绝大多数对象的生存周期都很短暂。
因为对象存活的周期较短,所以发生垃圾收集的次数较为频繁,存储此类对象的内存区域,称之为新生代区域。
强分代假说(Strong Generation Collection)熬过垃圾收集次数越多的对象就越难以消亡。
因为对象存活的周期较长,所以发生垃圾收集的次数较少,存储此类对象的内存区域,称之为老年代区域。
建立在分代收集理论上的收集算法 标记-清除算法(Mark-Sweep)顾名思义,该算法中包含了标记和清除两个动作。比较有意思的是,标记的是需要清除的,还是标记的是不需要清除的,需要根据具体情况来看,因为标记本身就是额外的开销,自然是越少越好。
比如在回收频繁的内存区域(新生代)中,那么其中的对象肯定回收动作发生很频繁,这个时候我们只标记不需要回收的对象就好了。让GC回收掉那些未被标记的对象。
又比如在内存回收不频繁的区域(老年代),我们只需要标记那些需要被回收的对象就好了,让GC收集器去回收掉就好了。
标记-复制算法(Mark-Copying)标记-复制算法的思路最开始是半区复制(Semispace Copying),那么何为半区复制呢?
半区复制是:把一块内存,分成大小相等的两块。内存分配只在其中一块上进行。当这一块上的内存用完时,就把这一块上面存活的对象标记出来,复制到另外的一块上去,再把之前那块上使用的内存空间清理掉,以此往复。
优点:假如大部分对象都是可回收的(新生代),那么这样的方式在移动时只需要移动堆顶指针即可,简单有效,快捷,也不用考虑空间碎片的情况。
问题很明显:可用的内存直接减少了一半。
不过针对可回收对象占大多数的情况,也有其他的 ”半区“复制。比如较为出名的Apple式回收。其思路在内存回收频繁(新生代)的区域,不是把内存分为大小为1:1的两块,而是分为8:1:1的三块内存区域。其中的8 + 1用于内存分配,剩下的1用于复制存活的对象,然后清除掉8+1上的内存空间,将清楚后的 8 + 1 中的1,留着用于下次复制。
当然了你会问:那如果存活的对象总大小大于1呢?那怎么办?这个问题的解决方案是:直接问其他内存区域借一点?问谁?问老年代借一点。对于超出的对象,放入老年代区域就好了。
标记-整理算法(Mark-Compac)标记-整理算法的思路类似于前文提到的标记-清除,但不同之处在于标记之后,还会整理一次内存区域。
具体体现为:将存活的对象往内存边界移动,然后清理掉除存活对象以外的内存区域。
注:本文图片来源–这里.



