通过上篇如何判断对象是否死亡,那么jvm要对死亡的对象进行垃圾回收,垃圾回收的算法主要有如下几种:java
该算法分为“标记”和“清除”阶段:首先标记出全部须要回收的对象,在标记完成后统一回收全部被标记的对象。它是最基础的收集算法,后续的算法都是对其不足进行改进获得。这种垃圾收集算法会带来两个明显的问题:算法
黑色表明要回收的对象,灰色表明不用回收的对象,白色表明空闲的内存。jvm
为了解决效率问题,“复制”收集算法出现了。它能够将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另外一块去,而后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。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
根据老年代的特色提出的一种标记算法,标记过程仍然与“标记-清除”算法同样,但后续步骤不是直接对可回收对象回收,而是让全部存活的对象向一端移动,而后直接清理掉端边界之外的内存。内存
标记整理算法解决了什么问题虚拟机
复制收集算法在对象存活率较高时就要进行较多的复制操做,效率将会变低。更关键的是,若是不想浪费 50%的空间,就须要有额外的空间进行分配担保,以应对被使用的内存中全部对象都 100%存活的极端状况,因此在老年代通常不能直接选用这种算法io
当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不一样将内存分为几块。通常将 java 堆分为新生代和老年代,这样咱们就能够根据各个年代的特色选择合适的垃圾收集算法。
好比在新生代中,每次收集都会有大量对象死去,因此能够选择复制算法,只须要付出少许对象的复制成本就能够完成每次垃圾收集。而老年代的对象存活概率是比较高的,并且没有额外的空间对它进行分配担保,因此咱们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。