当前位置: 首页 > 后端技术 > Java

JVM常用垃圾回收算法

时间:2023-04-02 00:53:50 Java

1、Mark-Sweepmark-sweep算法该算法分为“标记”和“清除”两个阶段:首先标记所有需要回收的对象,标记完成后,所有被标记的对象也可以依次标记存活的对象,统一回收所有未标记的对象。标记过程就是判断对象是否属于垃圾的过程。缺点:(1)执行效率不稳定:如果Java堆中包含大量对象,且大部分对象需要回收,此时必须进行大量的标记和清除动作,导致执行效率低下标记和清除两个过程。随着对象数量的增加而减少;(2)内存空间的碎片经过标记和清除后,会产生大量不连续的内存碎片。空间碎片太多可能导致程序运行时无法分配大对象。找到足够的连续内存,必须提前触发另一个垃圾收集操作。2.Copy复制算法mark-copy算法通常简称为复制算法。为了解决mark-sweep算法在面对大量可回收对象时执行效率低的问题,它将可用内存按照容量大小分成两块,并且只使用其中一块一个时间。当这块内存用完后,将存活的对象复制到另一块中,然后一次性清理掉已使用的内存空间。如果内存中的大部分对象都是存活的,这种算法会产生大量的内存到内存的复制开销,但是对于大部分对象都是可回收的情况,算法只需要复制少量存活的对象,而且每次都是回收整个半个区域的内存。分配内存时,无需考虑空间碎片的复杂情况。只需移动堆顶指针并按顺序分配即可。缺点:(1)浪费空间缺点也很明显。这种副本恢复算法的代价是将可用内存减少到原来的一半,空间的浪费有点太大了。3、Mark-Compact标记算法的标记过程还是和“mark-clear”算法一样,只是后面的步骤不是直接清理可回收对象,而是将所有存活的对象移动到最后内存空间,然后直接清理边界外的内存。缺点:(1)修改引用会消耗资源。在排序阶段移动幸存的对象并更新所有引用这些对象的地方将是一个非常繁重的操作,并且这种对象移动操作必须为整个过程暂停用户应用程序。根据各个算法的特点,还可以知道:在新生代存活对象不多的情况下,采用Copy算法;在老年代或许多幸存对象的情况下,使用Mark-Sweep和Mark-Compact算法。在G1之前的新一代分代垃圾收集器中,Serial、ParNew等收集器都是采用Copy算法来设计新一代的内存布局;ParallelScavenge收集器是基于mark-sort算法,而CMS收集器是基于mark-sweep算法的。4、三色标记算法G1和CMS都有并发标记垃圾的过程,即此时GC线程和工作线程同时工作,即非垃圾会变成垃圾(此时在下次回收时直接回收)可以清理掉,没有大的影响),垃圾变成非垃圾,如果垃圾变成非垃圾,如果不是及时发现并处理并回收利用,将造成非常严重的后果。JVM使用三色Marking算法来解决这类问题。将遍历中遇到的对象根据“是否被访问过”的情况标记为以下三种颜色:(1)白色:表示该对象没有被垃圾收集器访问过。(2)黑色:表示该对象已经被垃圾收集器访问过,所有对这个对象的引用都已经扫描过了。黑色物体代表已经扫描完毕,可以安全存活。如果有其他对象引用指向黑色对象,则无需重新扫描。黑色物体不可能直接(不经过灰色物体)指向某个白色物体。(3)灰色:表示该对象已经被垃圾收集器访问过,但是这个对象上至少有一个引用没有被扫描过。当且仅当同时满足以下两个条件时,才会出现错误回收的问题,即本应为黑色的对象被错误标记为白色:1.setter从黑色插入一个或多个新对象对象到白色对象。参考;2.评估者删除灰色对象对白色对象的所有直接或间接引用。因此,要解决这个并发标记的问题,我们只需要破坏这两个条件中的一个即可。于是产生了两种方案:增量更新(IncrementalUpdate)和原始快照(SnapshotAtTheBeginning,SATB)。1、增量更新需要破坏的是第一个条件。当黑色对象插入指向白色对象的新引用关系时,新插入的引用将被记录下来。并发扫描结束后,这些记录的引用将被记录下来。引用关系中的黑色对象为根,再次扫描。这可以简化为一旦新插入黑色对象并引用白色对象,它就会变回灰色对象。2、原始快照需要销毁的是第二个条件。当灰色对象要删除指向白色对象的引用关系时,它会记录要删除的引用。并发扫描结束后,这些记录的引用关系中的灰色对象就是根,重新扫描一遍。这也可以简单理解为,无论是否删除引用关系,都会根据刚开始扫描的那一刻对象图的快照进行查找。在HotSpot虚拟机中,增量更新和原始快照方案都有实际应用。比如CMS是基于增量更新的并发标记,G1和Shenandoah是用原始快照实现的。