深入学习 JVM 垃圾回收算法
博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌
Java知识图谱点击链接:体系化学习Java(Java面试专题)
💕💕 感兴趣的同学可以收藏关注下 ,不然下次找不到哟💕💕
1、如何判断对象死了吗?
在垃圾回收算法中,判断对象是否死亡是决定是否回收该对象的关键步骤。一般来说,有以下几种常见的对象死亡判断方法:
引用计数法(Reference Counting):引用计数法是一种简单的对象死亡判断方法,它通过记录对象被引用的次数来判断对象是否死亡。当对象的引用计数为0时,表示该对象不再被引用,可以被回收。但这种方法无法解决循环引用的问题,即两个或多个对象相互引用,导致引用计数不为0,但实际上这些对象已经不可达。
可达性分析法(Reachability Analysis):可达性分析法是一种更为常用的对象死亡判断方法。它通过判断对象是否可达来确定对象是否死亡。从根对象(如全局变量、静态变量等)出发,通过引用链追踪,如果一个对象无法通过任何引用链与根对象相连,则认为该对象不可达,即死亡,可以被回收。
根集合(Root Set):在可达性分析法中,根集合是指一组被直接或间接引用的对象,如全局变量、静态变量等。从根集合开始,通过引用链追踪,可以找到所有可达的对象。如果一个对象无法通过任何引用链与根集合相连,则认为该对象不可达,即死亡,可以被回收。
需要注意的是,判断对象是否死亡是垃圾回收算法的一部分,由垃圾回收器负责执行。不同的垃圾回收器可能采用不同的对象死亡判断方法,以提高垃圾回收的效率和准确性。
2、什么是垃圾回收算法
垃圾回收算法(Garbage Collection Algorithm)是指在计算机程序中,自动回收不再被使用的内存空间的一种算法。在Java中,垃圾回收算法是由Java虚拟机(JVM)负责执行的。
垃圾回收算法的目的是通过自动检测和回收不再被引用的对象,释放内存空间,从而避免内存泄漏和内存溢出的问题。垃圾回收算法可以根据不同的策略和算法来进行内存回收,常见的垃圾回收算法包括标记-清除算法、复制算法、标记-整理算法等。
3、都有哪些垃圾回收算法
常见的垃圾回收算法有以下几种:
标记-清除算法(Mark and Sweep):该算法首先标记出所有活动对象,然后清除未标记的对象。这种算法的缺点是会产生内存碎片,导致内存利用率降低。
复制算法(Copying):该算法将内存分为两个区域,每次只使用其中一个区域,当这个区域满了之后,将所有存活的对象复制到另一个区域,然后清除当前区域中的所有对象。这种算法的优点是不会产生内存碎片,但需要额外的内存空间。
标记-整理算法(Mark and Compact):该算法首先标记出所有活动对象,然后将所有存活的对象向一端移动,然后清除边界外的所有对象。这种算法的优点是不会产生内存碎片,但需要移动对象的开销。
分代收集算法(Generational Collection):该算法根据对象的存活时间将内存分为不同的代(Generation),一般将新创建的对象放入新生代,经过多次回收仍然存活的对象会被晋升到老年代。不同代使用不同的回收算法,如新生代使用复制算法,老年代使用标记-清除或标记-整理算法。
除了以上常见的垃圾回收算法,还有一些特殊的算法,如增量式收集算法、并发收集算法等。这些算法在特定场景下可以提供更高效的垃圾回收性能。不同的垃圾回收器和Java虚拟机实现可能会选择不同的垃圾回收算法来进行内存回收。
4、标记-清除算法
4.1、标记-清除算法的原理
标记-清除算法(Mark and Sweep)是一种常见的垃圾回收算法,用于标记和清除不再被使用的对象。它的工作原理如下:
标记阶段(Mark):
- 从根对象开始,通过引用链追踪,遍历所有可达的对象。
- 对于每个可达对象,将其标记为“活动”(即存活状态)。
- 对于未标记的对象,即为“非活动”(即死亡状态)。
清除阶段(Sweep):
- 遍历整个堆内存,对于每个对象:
- 如果该对象是活动的,则保留。
- 如果该对象是非活动的,则将其回收,释放其占用的内存空间。
- 遍历整个堆内存,对于每个对象:
标记-清除算法的优点是能够准确地找到不再被使用的对象,并将其回收。然而,它也存在一些缺点:
- 内存碎片:由于清除阶段只是简单地将非活动对象回收,而不进行内存整理,因此会产生内存碎片。这些碎片可能会导致内存利用率降低,使得分配大对象或连续内存空间变得困难。
- 垃圾回收暂停:在标记和清除阶段,垃圾回收器需要遍历整个堆内存,这可能会导致应用程序的停顿时间增加,影响系统的响应性能。
为了解决标记-清除算法的缺点,还有其他更高级的垃圾回收算法被开发出来,如复制算法、标记-整理算法和分代收集算法。这些算法通过不同的方式来解决内存碎片和暂停时间的问题,提供更高效的垃圾回收性能。
4.2、标记-清除算法的优缺点
标记-清除算法(Mark and Sweep)是一种常见的垃圾回收算法,用于标记和清除不再被使用的对象。它的优点和缺点如下:
优点:
准确性:标记-清除算法能够准确地找到不再被使用的对象,并将其回收,确保不会误删活动对象。
灵活性:该算法适用于任何类型的对象,不受对象之间的引用关系限制。
简单实现:相对于其他复杂的垃圾回收算法,标记-清除算法的实现比较简单,容易理解和实现。
缺点:
内存碎片:标记-清除算法在回收非活动对象时不进行内存整理,导致内存空间出现碎片化。这可能会降低内存利用率,并使得分配大对象或连续内存空间变得困难。
垃圾回收暂停:在标记和清除阶段,垃圾回收器需要遍历整个堆内存,这可能会导致应用程序的停顿时间增加,影响系统的响应性能。
不适用于大型堆内存:标记-清除算法对于大型堆内存的垃圾回收效率较低。随着堆内存的增长,标记和清除的时间也会线性增加。
为了解决标记-清除算法的缺点,还有其他更高级的垃圾回收算法被开发出来,如复制算法、标记-整理算法和分代收集算法。这些算法通过不同的方式来解决内存碎片和暂停时间的问题,提供更高效的垃圾回收性能。
5、复制算法
5.1、复制算法的原理
复制算法(Copying Algorithm)是一种常见的垃圾回收算法,用于解决标记-清除算法中的内存碎片问题。其原理如下:
将堆内存分为两个区域,通常称为From空间和To空间。初始时,所有的活动对象都存储在From空间中。
当需要进行垃圾回收时,从根对象开始,通过引用链追踪,将所有可达的对象复制到To空间中。这个过程中,对象的引用关系被更新为To空间中的新地址。
复制完成后,From空间中的所有对象都是非活动对象,可以被直接回收。
交换From空间和To空间的角色,使得To空间成为新的From空间,From空间成为新的To空间。
下一次垃圾回收时,重复上述过程,将活动对象复制到新的To空间中。
复制算法的优点是解决了标记-清除算法中的内存碎片问题,因为每次垃圾回收后,所有活动对象都被紧凑地存储在To空间中,不会产生碎片。同时,复制算法也具有一些缺点:
需要额外的空间:由于需要同时维护两个空间,复制算法需要至少两倍的堆内存空间。
对象复制开销:每次垃圾回收时,需要将所有活动对象复制到新的空间中,这会引入一定的复制开销。
为了克服复制算法的缺点,还有其他更高级的垃圾回收算法被开发出来,如标记-整理算法和分代收集算法。这些算法通过不同的方式来减少额外空间的使用和对象复制的开销,提供更高效的垃圾回收性能。
5.2、复制算法优缺点
复制算法(Copying Algorithm)是一种常见的垃圾回收算法,用于解决标记-清除算法中的内存碎片问题。它的优点和缺点如下:
优点:
内存整理:复制算法将活动对象紧凑地存储在To空间中,不会产生内存碎片,提高了内存利用效率。
简单高效:复制算法实现简单,只需要维护两个空间,并且垃圾回收过程中只需要复制活动对象,减少了回收时间。
缺点:
额外空间开销:复制算法需要至少两倍的堆内存空间,因为需要同时维护From空间和To空间。
对象复制开销:每次垃圾回收时,需要将所有活动对象复制到新的空间中,这会引入一定的复制开销。
不适用于大型对象:如果有大型对象需要复制,复制开销会更大。
需要注意的是,复制算法适用于短暂存活时间的对象,而不适用于长时间存活的对象。为了克服复制算法的缺点,还有其他更高级的垃圾回收算法被开发出来,如标记-整理算法和分代收集算法,它们通过不同的方式来减少额外空间的使用和对象复制的开销,提供更高效的垃圾回收性能。
6、标记-整理算法
6.1、标记-整理算法的原理
标记-整理算法(Mark-Sweep Algorithm)是一种常见的垃圾回收算法,用于解决标记-清除算法中的内存碎片问题。其原理如下:
首先,从根对象开始,通过引用链追踪,标记所有的活动对象。标记过程中,将活动对象的标记位设置为有效状态。
完成标记后,将所有的活动对象紧凑地移动到堆内存的一端,即进行整理。整理过程中,将活动对象按照内存地址顺序依次排列,不会产生内存碎片。
整理完成后,从堆内存的另一端开始,将非活动对象回收。回收过程中,将非活动对象的内存空间释放,以便下次分配给新的对象使用。
标记-整理算法的优点是解决了标记-清除算法中的内存碎片问题,因为整理过程中将活动对象紧凑地存储在一起,不会产生碎片。同时,标记-整理算法也具有一些缺点:
整理开销:整理过程需要移动活动对象,可能会引入一定的整理开销。
需要额外空间:为了进行整理,需要额外的空间来存储活动对象。
为了克服标记-整理算法的缺点,还有其他更高级的垃圾回收算法被开发出来,如分代收集算法。这些算法通过不同的方式来减少整理开销和额外空间的使用,提供更高效的垃圾回收性能。
6.2、标记-整理算法的优缺点
标记-整理算法(Mark-Sweep Algorithm)是一种常见的垃圾回收算法,它的优点和缺点如下:
优点:
解决了标记-清除算法的内存碎片问题:标记-整理算法在回收垃圾对象的同时,会将存活的对象紧凑地移动到一端,从而解决了内存碎片的问题。
提高了内存利用效率:整理过程中,将活动对象紧凑存储,可以更好地利用内存空间。
缺点:
整理开销较大:标记-整理算法需要将存活的对象进行整理,可能需要移动对象的位置,这会引入一定的整理开销。
需要额外的空间:为了进行整理,标记-整理算法需要额外的空间来存储活动对象,这会增加内存的使用量。
不适用于长生命周期的对象:对于长生命周期的对象,由于需要进行整理和移动,标记-整理算法的效率可能较低。
需要注意的是,标记-整理算法适用于短生命周期的对象,而对于长生命周期的对象,更适合使用分代收集算法等其他高级垃圾回收算法。
7、分代收集算法
7.1、分代收集算法的原理
分代收集算法是一种常见的垃圾回收算法,根据对象的生命周期将堆内存划分为不同的代(Generation),并针对每个代采取不同的回收策略。其原理如下:
将堆内存分为不同的代:通常将堆内存分为新生代(Young Generation)和老年代(Old Generation)两个代。新生代用于存储新创建的对象,而老年代用于存储存活时间较长的对象。
新生代的回收策略:新生代采用复制算法(Copying Algorithm)。新创建的对象首先被分配到新生代的一个区域(通常称为Eden区)。当Eden区满时,会触发Minor GC(新生代垃圾回收),将存活的对象复制到新生代的另一个区域(通常称为Survivor区)。经过多次Minor GC后,仍然存活的对象会被晋升到老年代。
老年代的回收策略:老年代采用标记-清除算法(Mark-Sweep Algorithm)或标记-整理算法(Mark-Compact Algorithm)。当老年代的空间不足时,会触发Major GC(老年代垃圾回收)。首先进行标记阶段,标记所有的存活对象。然后,根据选择的回收策略,进行清除或整理操作。标记-清除算法会将非存活对象直接回收,而标记-整理算法会将存活对象整理到一端,然后回收剩余的空间。
混合回收:某些分代收集算法还可以采用混合回收(Mixed GC)的方式。混合回收指同时对新生代和老年代进行回收,可以减少回收时的停顿时间。
分代收集算法的优点是根据对象的生命周期采取不同的回收策略,可以更有效地回收垃圾对象,提高垃圾回收的效率。同时,通过将堆内存划分为不同的代,可以更好地适应不同对象的存活特性。然而,分代收集算法也增加了算法的复杂性,并且需要更多的内存用于存储分代信息。
7.2、分代收集算法的优缺点
分代收集算法的优点和缺点如下:
优点:
提高垃圾回收效率:分代收集算法根据对象的生命周期采取不同的回收策略,针对不同代的特点进行优化,可以更有效地回收垃圾对象,提高垃圾回收的效率。
减少停顿时间:通过将堆内存划分为不同的代,可以将垃圾回收的工作分散到不同的时间段,从而减少每次回收时的停顿时间,提高应用程序的响应性能。
适应不同对象的存活特性:分代收集算法可以根据对象的存活时间将其分配到不同的代中,从而更好地适应不同对象的存活特性,提高内存利用效率。
缺点:
增加算法复杂性:分代收集算法相对于其他简单的垃圾回收算法来说,具有更复杂的实现和管理逻辑,增加了算法的复杂性。
需要更多的内存:分代收集算法需要额外的内存用于存储分代信息,这会增加内存的使用量。
需要更多的计算资源:由于分代收集算法需要对不同代的对象采取不同的回收策略,因此需要更多的计算资源来管理和执行垃圾回收操作。
需要注意的是,分代收集算法适用于大部分应用场景,但对于某些特殊的应用程序或特定类型的对象,可能需要使用其他更为高级的垃圾回收算法来进行优化。
💕💕 本文由激流原创
💕💕喜欢的话记得点赞收藏啊
- 点赞
- 收藏
- 关注作者
评论(0)