垃圾收集算法

标记-清除算法

标记-清除算法是最基础的算法,算法分为“标记”和“清除”两个阶段:

  1. 标记:首先标记出所有需要回收的对象,标记过程可以参考《深入理解JAVA虚拟机》学习笔记–对象存活算法
  2. 清除:对标记的对象进行清除。
缺点:
  • 效率,标记和清除两个过程的效率都不高。
  • 空间,标记清除后会产生大量的不连续内存碎片,在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

复制算法

为了解决 效率 的问题,一种称为 “复制” 的收集算法出现了,它将内存按容量划分为大小相等的两块,每次只使用其中一块。当这一块内存用完后,就将还存活的对象复制到另外一块上,然后再把已使用过的内存空间一次清理掉。这种算法解决了内存碎片的复杂情况,但是代价是将内存缩小为了原来的一半。
HotSpot 并没有按照 1:1 的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的 Survivor 空间,比例为 8:1:1。
当回收时,将Eden和Survivor中还存活着的对象一次性地复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。这样每次新生代中可用内存空间为整个新生代容量的90%(80%+10%) ,只有10%的内存会被“浪费”。

标记-整理算法

复制收集算法在对象存活率较高时,就要进行较多的复制操作,效率会变低。更关键的是,如果不想浪费50%的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。
固针对老年代的特点,提出了另一种“标记-整理”算法,具体过程为:

  1. 标记:标记过程与“标记-清除”算法的标记一样。
  2. 整理:将所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

分代收集算法

当前商业虚拟机的垃圾收集都采用分代收集算法,这种算法的思想是 “根据对象存活周期的不同将内存划分为几块,对不同区域采用不同的收集算法” 。

  • 新生代:新生代每次收集进都有大批对象死去,只有少量存活,采用 复制算法 只需要付出少量的存活对象复制成本就可以完成收集。
  • 老年代:因为对象存活率高、没有额外空间对它进行分配担保,就必须使用 标记-整理标记-清除 算法来进行回收。