本文参考自周志明的《深入理解java虚拟机》,这本书写的非常好!非常推荐!
注意:各个平台的算法实现不尽相同。
1.Mark-Sweep算法(标记清除)
步骤:
首先标示需要清除的对象。
标记完成之后,统一回收掉被标记的对象。
缺点:
效率问题:标记清除过程效率都不高。
标记清除之后会产生大量的不连续的内存碎片。(空间碎片太多导致无法找到连续的空间用以分配较大的对象,而引起一次垃圾回收行为。)
2.Copying收集算法(复制算法)基于标记清除算法
步骤:
A.把可用内存划分为大小相等的两块。
B.每次使用其中一块。
C.当其中一块时候完的时候,就将还存活的对象复制到另外一块上去。
D.把已使用过的内存空间一次清理掉。
优点:
不必考虑内存碎片问题。
实现简单,运行高效。
缺点:
内存减少为原来的一半。
对象存活率较高的时候就要执行较多的复制操作。
如果不使用50%的对分策略,老年代需要考虑的空间担保策略。
演进:并不需要根据1:1划分内存空间,而是将内存划分为一块较大的EdenSpace和两块较小的SurvivorSpace。
JavaHeap内存回收模型(当前商业虚拟机大多使用此算法回收新生代)
3.Mark-Compact算法(标记整理算法)基于标记清除算法
由于复制算法的缺点,及老年代的特点(存活率高,没有额外内存对其进行空间担保),老年代一般不使用复制算法。
步骤:
标记不再使用的对象。
让存活的对象向内存的一段移动。
清理掉边界以外的内存。
由于老年代存活率高,没有额外内存对老年代进行空间担保,那么老年代只能采用标记-清理算法或者标记整理算法。
4.Generational Collection(分代收集算法)
当前的商业虚拟机的垃圾收集都采用,把Java堆分为新生代和老年代。根据各个年代的特点采用最适当的收集算法。
Java所提倡的内存管理主要解决了两个问题:
给对象分配内存。
回收给对象分配的内存。
分配以及回收策略
大多数情况,对象在新生代的Edenspace分配。
当EdenSpace区没有足够空间进行分配时,虚拟机将发起一次MinorGC(Minor GC是指发生在新生代的垃圾回收动作。Major、FullGC是指发生在老年代的GC)。
大对象(需要大量连续空间的Java对象)直接进入老年代。这样做避免了在EdenSpace和两个Survivor区之间发生大量的内存拷贝。
长期存活的对象将进入老年代。(生活在Edenspace和SurvivorSpace的对象经过MinorGC,确定年龄,到达一定年龄后晋升到老年代。
如果在SurvivorSpace中相同年龄的所有对象大小总和大于Survivor空间的一半。则年龄大于或等于该年龄的对象将直接进入老年代,而无需等待到达要求的年龄。
空间担保。