谁生?谁死?从引用计数到可达性分析,洞悉GC的决策逻辑

引用计数与可达性分析:谁死了,谁还活着?

垃圾回收,顾名思义,便是将已经分配出去的,但却不再使用的内存回收回来,以便能够再次分配。在Java虚拟机的语境下,垃圾指的是死亡的对象所占据的堆空间。这里便涉及了一个关键的问题:如何辨别一个对象是存是亡?

引用计数

引用计数(Reference Counting)是一种古老的辨别方法,它的基本思想是给每个对象添加一个引用计数器,每当有一个引用指向该对象时,计数器就加1;每当有一个引用停止指向该对象时,计数器就减1。当计数器的值变为0时,就表示没有任何引用指向该对象,因此该对象就成为垃圾,

引用计数的主要问题是无法处理循环引用(Reference Cycle)的情况。例如,如果对象A和对象B互相引用,那么即使没有其他引用指向它们,它们的引用计数器也不会变为0,因此它们不会被回收,这就导致了内存泄漏。这是引用计数最大的缺点,也是它在许多现代编程语言中不被使用的主要原因。

另外,引用计数需要在每次引用赋值时更新引用计数器,这会带来一定的性能开销。而且,如果多个线程同时修改同一个对象的引用计数器,还需要进行同步,这会进一步增加性能开销。

可达性分析

Java虚拟机的主要采取的是可达性分析(Reachability Analysis)。这个算法是通过一系列的称为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

GC Roots通常是由堆外指向堆内的引用,包括以下几种。

1)虚拟机栈(栈帧中的本地变量表)中引用的对象;

2)方法区中类静态属性引用的对象;

3)方法区中常量引用的对象;

4)本地方法栈中JNI(即一般说的Native方法)引用的对象。

可达性分析可以解决引用计数所不能解决的循环引用问题。例如,即便对象A和B相互引用,只要从GC Roots出发无法到达A或者B,那么可达性分析便不会将它们加入存活对象合集之中。

尽管可达性分析的算法本身很直观,但在实际应用中,还需要解决一些其他问题,如误标和漏标。

1)误标:将已经不再使用的对象错误地标记为"活的"。例如,一个全局静态对象引用了一个已经不再需要的局部对象,它会被错误地标记为"活的"。

2)漏标:将仍在使用的对象错误地标记为"死的"。例如,在并发环境中,一个线程正在使用一个对象,而另一个线程正在进行垃圾回收。如果垃圾回收线程看到的是一个过时的对象引用关系,它可能会错误地认为一个正在使用的对象是"死的"。

误报可能导致Java虚拟机错过部分垃圾回收的机会。而漏报更麻烦,因为垃圾回收器可能会错误地回收仍被引用的对象内存。如果试图从原引用访问已经被回收的对象,可能会导致Java虚拟机崩溃。

Stop-the-world 以及安全点

为了避免这些问题,Java虚拟机的传统垃圾回收算法采用了Stop-the-world方式。在此阶段,Java虚拟机会暂停所有的应用线程,确保在垃圾回收过程中不会有新的对象被创建,也不会有对象引用关系的变化。但这会导致应用程序的响应时间增加,因为在这个阶段,所有的应用线程都被暂停,应用程序无法响应用户的请求。

安全点(Safe Point)是Java虚拟机用来控制Stop-the-World的一种机制。安全点是指那些可以安全地暂停应用线程的点。在这些点上,Java虚拟机可以确保对象引用关系不会发生变化。常见的安全点有方法调用(包括JNI方法调用)、循环跳转、异常抛出等。其中方法调用是一个很好的安全点,因为方法调用通常涉及到大量的对象引用操作。

对于解释执行,当有安全点请求时,Java虚拟机可以在每条字节码指令后面都设置一个安全点,但这种方式的开销很大。在执行即时编译器生成的机器码时,Java虚拟机通常会在方法的入口和退出处,以及循环的回边处设置安全点。另外当线程阻塞时,由于处于Java虚拟机线程调度器的掌控之下,因此可以设置安全点。

未完待续

很高兴与你相遇!如果你喜欢本文内容,记得关注哦

相关推荐
shuidaoyuxing13 小时前
对 微服务 进行一次系统化、结构化的全面讲解
微服务·云原生·架构
7ioik13 小时前
什么是线程池?线程池的作用?线程池的四种创建方法?
java·开发语言·spring
切糕师学AI13 小时前
Lombok 注解 @Slf4j
java·lombok
晨非辰13 小时前
数据结构排序系列指南:从O(n²)到O(n),计数排序如何实现线性时间复杂度
运维·数据结构·c++·人工智能·后端·深度学习·排序算法
小曹要微笑14 小时前
STM32H7系列全面解析:嵌入式性能的巅峰之作
c语言·stm32·单片机·嵌入式硬件·算法
寻星探路14 小时前
JavaSE重点总结后篇
java·开发语言·算法
EAIReport14 小时前
自动化报告生成产品内嵌OA/BI平台:解决传统报告痛点的技术方案
java·jvm·自动化
工具人555514 小时前
复制cmd窗口所有文字快捷方式
服务器
Charles_go15 小时前
C#中级8、什么是缓存
开发语言·缓存·c#
RoboWizard15 小时前
高性能电脑热战寒冬 11月DIY配置推荐
linux·运维·服务器·电脑·金士顿