jvm 垃圾收集算法

通过上篇如何判断对象是否死亡,那么jvm要对死亡的对象进行垃圾回收,垃圾回收的算法主要有如下几种:java

1、标记-清楚算法

该算法分为“标记”和“清除”阶段:首先标记出全部须要回收的对象,在标记完成后统一回收全部被标记的对象。它是最基础的收集算法,后续的算法都是对其不足进行改进获得。这种垃圾收集算法会带来两个明显的问题:算法

  • 一个是效率问题,标记和清除两个过程的效率都不高
  • 一个是空间问题,标记清除以后会产生大量不连续的内存碎片,空间碎片太多可能会致使之后在程序运行过程当中须要分配较大对象时,没法找到足够的连续内存而不得不提早触发另外一次垃圾收集动做

黑色表明要回收的对象,灰色表明不用回收的对象,白色表明空闲的内存。jvm

2、复制算法

为了解决效率问题,“复制”收集算法出现了。它能够将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另外一块去,而后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。spa

这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂状况,只要移动堆顶指针,按顺序分配内存便可,实现简单,运行高效。指针

如今的商业虚拟机都采用这种收集算法来回收新生代,研究代表,新生代中的对象 98%是“朝生夕死”的,因此并不须要按照 1:1 的比例来划份内存空间,而是将内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 和其中一块 Survivor。 Survivor from 和Survivor to ,内存比例 8:1:1对象

当回收时,将 Eden 和 Survivor 中还存活着的对象一次性地复制到另一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor 空间。HotSpot 虚拟机默认 Eden 和 Survivor 的大小比例是 8:1, 也就是每次新生代中可用内存空间为整个新生代容量的 90% (80%+10%),只有 10% 的内存会被“浪费”。固然,98%的对象可回收只是通常场景下的数据,咱们没有办法保证每次回收都只有很少于 10%的对象存活,当 Survivor 空间不够用时,须要依赖其余内存(这里指老年代)进行分配担保(Handle Promotion)。blog

3、标记-整理算法

根据老年代的特色提出的一种标记算法,标记过程仍然与“标记-清除”算法同样,但后续步骤不是直接对可回收对象回收,而是让全部存活的对象向一端移动,而后直接清理掉端边界之外的内存。内存

标记整理算法解决了什么问题虚拟机

复制收集算法在对象存活率较高时就要进行较多的复制操做,效率将会变低。更关键的是,若是不想浪费 50%的空间,就须要有额外的空间进行分配担保,以应对被使用的内存中全部对象都 100%存活的极端状况,因此在老年代通常不能直接选用这种算法io

4、分代收集算法

当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不一样将内存分为几块。通常将 java 堆分为新生代和老年代,这样咱们就能够根据各个年代的特色选择合适的垃圾收集算法。

好比在新生代中,每次收集都会有大量对象死去,因此能够选择复制算法,只须要付出少许对象的复制成本就能够完成每次垃圾收集。而老年代的对象存活概率是比较高的,并且没有额外的空间对它进行分配担保,因此咱们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。

相关文章
相关标签/搜索