垃圾回收算法

常见的垃圾回收算法有

  • 标记-清除算法
  • 标记-复制算法
  • 标记-整理算法

标记-清除算法

该算法分为两个阶段,标记清除

  • 标记:标记出所有需要回收的对象,或者标记处所有不需要回收的对象
  • 清除:将需要回收的对象从内存中回收

使用标记-清除算法进行垃圾回收,会有几个缺点

  • 效率不稳定,随着对象的增多,标记的效率会越来越低
  • 内存碎片,由于只是将内存中的部分垃圾对象直接回收,没有对内存进行整理,在执行垃圾回收后,会产生大量的不连续的内存空间,接下来在新的对象分配时,可能很快就因为没有足够大的连续的内存空间来分配导致触发垃圾回收

标记-复制算法

常被称为复制算法

该算法将整个内存分为大小相等的两部分,每次分配对象时只用其中一块,当这块内存快用完时,对其进行回收,把这块内存中的所有的存活对象标记出来,然后复制到另一块未被使用的内存中去

使用标记-复制算法不会产生大量的内存碎片,但是它也有自己的缺点

  • 内存使用率低,每次只使用整个内存的一半
  • 当内存中存活对象较多时,复制效率较低

为了解决这个问题,在部分虚拟机,如HotSpot,对采用标记-复制算法的新生代做如下处理

  • 将新生代划分为Eden区、SurvivorTo区、SurvivorFrom区
  • E:Sto:Sfrom = 8:1:1
  • 新对象优先分配在Eden区,发生MinorGC后,如果S区能够放下,就复制到S区
  • 下次GC时,如果另一个S区能够放下当前存活的所有对象,就把S+E区的对象都复制到该S区,然后清空S和E区
  • 如果S区中无法放下所有的存活对象,还会触发虚拟机的空间分配担保机制(handle promotion),这个机制的主要作用就是,可以将新生代S区放不下的对象直接放入老年代

这样,内存的使用率就从50%上升到了90%,因为在新生代中,绝大多数的对象都是可以被快速回收的,甚至熬不过一轮GC

标记-整理算法

该算法在标记完存活对象后,会将所有的存活对象移动到内存的一侧,然后直接对另一侧内存进行回收

使用该算法进行垃圾回收,不会产生任何内存碎片,因为它对内存进行了整理

该算法的缺点

  • 因为需要移动对象,所以其耗时会比不移动对象的算法(如,标记-清理)大