目录
前言
判断对象是否存活
引用计数算法
可达性分析算法
GC Root的产生
Java中的四种引用类型
1.强引用
强引用弱化方式
方式1:使对象指向null
方式2:使对象超出作用域范围
2.软引用
3.弱引用
4.虚引用
垃圾收集算法
分代收集理论
垃圾收集算法分类
1.标记-清除算法(Mark-Sweep)
标记-清除算法的特点或问题
2.标记-复制算法(Copying)
算法工作流程
标记-复制算法的特点
3.标记-整理算法(Mark-Compact)
算法工作流程
标记-整理算法的特点
总结
前言
Java中的垃圾收集器(Garbage Collector)负责管理堆内存中的对象,回收不再使用的对象以释放内存空间。
判断对象是否存活
垃圾收集器工作的前提是该对象确实为一个垃圾对象,因此在 回收前需要进行判断,这里有两种方式可以对对象进行判断,分别是引用计数算法和可达性分析算法
引用计数算法
引用计数算法是通过在对象中添加一个引用计数器,来记录该对象被其他对象引用的次数,当计数器为0的时候,表示该对象没有被其他对象引用,是一个可回收的垃圾对象。
当然,这种算法存在一个较明显的问题,就是无法应对对象的循环引用,例如a
对象引用了 b
对象,b
对象也引用了 a
对象,a
、b
对象却没有再被其他对象所引用了,其实正常来说这两个对象已经是垃圾了,因为没有其他对象在使用了,但是计数器内的数值却不是 0
,所以引用计数算法就无法回收它们。
可达性分析算法
可达性分析算法是通过引用链确认对象是否可用,也就是说在引用链上的对象即为可用对象,否则为垃圾对象。在该引用链上定义了“GC Root”起始节点集,引用链上的每个对象都可以通过GC Root找到。
例如下图中,Object 6
、Object 7
、Object 8
彼此之前有引用关系,但是没有与"GC Roots"相连,那么就会被当做垃圾所回收。
GC Root的产生
- 栈帧中的本地变量和参数:正在执行的方法中的本地变量和参数可以作为GC Root,因为它们是当前线程活动的一部分。
- 静态变量:类的静态变量通常存储在方法区中,它们随着类的加载而被创建,并且在整个程序运行期间一直存在,因此它们被视为GC Root。
- 虚拟机内部的特殊引用:例如常量引用、系统类加载器等。
- JNI引用:在Java代码中使用了JNI(Java Native Interface)时,如果在本地代码中使用全局引用或弱全局引用,它们也会作为GC Root。
Java中的四种引用类型
垃圾回收器的工作时机除了与本身使用的算法相关,还与对象本身的引用类型相关。
1.强引用
强引用是最常使用的引用,通常是指向new 出来的对象的引用 例如 Object strongReference = new Object();,对于强引用,垃圾回收器是绝对不会进行回收操作的。就算是在内存空间不足的情况下,JVM也会通过抛出OutOfMemory来终止程序,而非回收强引用。
强引用弱化方式
强引用对象也存在不使用的情况,它的回收需要通过弱化,从而使垃圾回收器回收
方式1:使对象指向null
此时垃圾回收器会认为该对象不存在引用,然后根据GC算法对该对象进行回收。
例如:ArrayList集合的clear方法,就是通过遍历数组,将数组中的每个引用都指向null,使垃圾回收器能够对对象进行回收,达到清空的效果。
方式2:使对象超出作用域范围
在Java中,对象的作用域通常由大括号({})来定义,包括类、方法和代码块。当对象的作用域结束时,即离开了其定义的代码块或方法,该对象就会超出其作用域范围。
简单来说就是当一个对象在其作用域内被创建时,在该作用域范围内,可以通过引用来访问和操作该对象。但是一旦离开了对象的作用域,该对象就不能再通过原有的引用来访问和操作了。比如说对象对象定义在方法内,当方法执行结束,JVM方法栈中的活动栈帧弹出时,该对象也就不在作用域范围内了。
2.软引用
软引用也是一种较强的引用类型,与强引用的不回收不同,软引用可以在内存空间补不足时被垃圾回收器回收。通常用于内存敏感内容的高速缓存。
举个例子,在下图中,模拟了一个软引用,分别测试内存溢出与内存不溢出的情况下,断开引用后,软引用中的值
内存充沛
内存不足
在上面的例子上我们可以看到,当内存充足的情况下,即使软引用指向null,也不会被回收,一旦内存不足,软引用则被回收。
3.弱引用
弱引用是一种比软引用更弱的引用类型,与软引用不同,弱引用在下一次垃圾回收时一定会被垃圾回收器回收,无论内存是否充足。
4.虚引用
虚引用是最弱的一种引用关系,如果一个对象仅持有虚引用,完全不会对其生存时间构成影响,它就和没有任何引用一样,随时可能会被回收。它主要用来跟踪对象被垃圾回收的活动,可以在垃圾收集时收到一个系统通知。
在 JDK1.2
之后,用 PhantomReference
类来表示,通过查看这个类的源码,发现它只有一个构造函数和一个 get()
方法,而且它的 get()
方法仅仅是返回一个null
,也就是说将永远无法通过虚引用来获取对象。
垃圾收集算法
说到垃圾收集算法就不得不说一个重要理论,即分代收集理论。下文详细介绍:
分代收集理论
分代收集理论基于一个观察:将对象的生命周期通常可以被划分为不同的阶段或代。根据对象的生命周期,垃圾回收器可以将内存划分为不同的代,然后针对不同代的对象应用不同的垃圾回收策略。目前主流JVM的垃圾收集器都遵循分代收集理论。
一般来说,分代收集理论将内存划分为至少两个代:年轻代、老年代
这是由于大部分对象在被创建后一段时间内会被频繁使用,但随着时间的推移,它们的生命周期会逐渐延长。因此,分代收集理论认为大部分对象是临时的,并且在它们的年轻阶段就会被回收,而只有部分对象会存活更久并进入老年代。
年轻代
被创建后一段时间内会被频繁使用,但随着时间的推移,它们的生命周期会逐渐延长。因此,分代收集理论认为大部分对象是临时的,并且在它们的年轻阶段就会被回收,而只有部分对象会存活更久并进入老年代。
老年代
在老年代中,垃圾回收器采用更长的回收周期和较少的垃圾回收操作。这是因为老年代中的对象通常具有较长的生命周期,并且相对稳定。典型的垃圾回收策略是标记-清除(Mark-Sweep)或标记-压缩(Mark-Compact)算法,其中垃圾回收器会标记并清除或压缩无效的对象,并回收相应的内存空间。
垃圾收集算法分类
1.标记-清除算法(Mark-Sweep)
标记-清除算法的整个工作过程可以分为两个阶段,分别是“标记”和“清除”。在标记阶段,首先垃圾收集器会标记出所有不需要回收的对象(这可以通过在对象的头部添加一个标记位来实现),然后进入清除阶段,将未标记的对象回收。
标记-清除算法的特点或问题
A.效率问题:
如果执行垃圾收集的区域中,大部分对象是需要被回收的,则需要哦执行大量的标记和清除操作,导致效率变低。
B.内存空间问题:
标记清除后会产生大量不连续的碎片,空间碎片太多,会导致分配较大对象时,无法找到足够的连续空间,从而会触发新的垃圾收集动作。
C.暂停时间:
在标记和清除阶段中,垃圾回收器需要停止应用程序的执行,这可能导致较长的停顿时间,影响应用的响应性。
2.标记-复制算法(Copying)
标记-复制算法在内存上的维护上,将空间分成两个大小相同的区域,通常称为对象区域和空闲区域。
算法工作流程
- 初始化时,所有对象都在对象区域。
- 从根对象开始,标记所有可达对象,将其从对象区域复制到空闲区域,并在新位置上更新引用。
- 完成复制后,对象区域中所有未被复制的对象都被认为是垃圾。
- 清空对象区域,并将空闲区域与对象区域交换,使空闲区域变为下一次垃圾回收的对象区域。
- 重复上述过程,进行下一轮的垃圾回收。
标记-复制算法的特点
A.高效的分配:
由于复制过程中对象是连续存放的,新对象的分配只需要简单的移动指针,效率较高。
B.暂停时间可控:
由于只需要复制存活对象,标记阶段的垃圾回收工作量相对较小,可以有效限制暂停时间。
C.内存利用率相对较低:
标记-复制算法会将堆内存的一半用于复制存活对象,因此相对于标记-清除算法会有一定的内存浪费。
D.效率降低
在对象存活率较高的情况下,需要进行较多内存间复制,导致效率降低
3.标记-整理算法(Mark-Compact)
标记-整理算法的主要思想是在标记阶段标记所有可达对象,并在标记完成后进行整理。整理阶段会将存活的对象向一端移动,然后清理掉边界之外的无效对象,以达到内存整理的目的。
算法工作流程
- 从根对象开始,标记所有可达对象。
- 在标记完成后,将存活对象向一端移动,并保持它们的相对顺序不变。这样,所有存活对象就在内存的一段连续区域中。
- 在移动过程中,将无效对象所占用的内存空间进行回收。可以通过向移动后存活对象的新位置复制数据来完成这一步骤。
- 清理掉边界之外的无效对象所占用的内存空间,使其变为可用于分配新对象的空闲内存。
标记-整理算法的特点
A.解决内存碎片化:
通过将存活对象移动到一端,并清理边界之外的无效对象,可以实现内存的整理,解决内存碎片问题。
B.高效的分配:
由于整理后存活对象在一段连续区域中,新对象的分配只需要简单的移动指针,效率较高。
C.暂停时间可控:
标记-整理算法的标记和整理阶段可以分别进行,可以有效限制暂停时间。文章来源:https://www.toymoban.com/news/detail-709523.html
总结
标记-整理算法适用于老年代,而在年轻代通常采用其他垃圾回收算法,如标记-复制算法或其他更适合的算法。标记-整理算法通常与年轻代的标记-复制算法或其他算法配合使用,以实现整个堆的高效垃圾回收。文章来源地址https://www.toymoban.com/news/detail-709523.html
到了这里,关于Java垃圾收集机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!