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

垃圾回收,顾名思义,便是将已经分配出去的,但却不再使用的内存回收回来,以便能够再次分配。在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虚拟机线程调度器的掌控之下,因此可以设置安全点。

未完待续

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

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

  1. JVM中垃圾回收机制如何判断是否死亡?详解引用计数法和可达性分析 !

    因为热爱,所以坚持. 文章下方有本文参考电子书和视频的下载地址哦~ 这节我们主要讲垃圾收集的一些基本概念,先了解垃圾收集是什么.然后触发条件是什么.最后虚拟机如何判断对象是否死亡. 一.前言   我们 ...

  2. JVM 基础:回收哪些内存/对象 引用计数算法 可达性分析算法 finalize()方法 HotSpot实现分析

    转自:https://blog.csdn.net/tjiyu/article/details/53982412 1-1.为什么需要了解垃圾回收 目前内存的动态分配与内存回收技术已经相当成熟,但为什么还 ...

  3. java中垃圾回收机制中的引用计数法和可达性分析法(最详细)

    首先,我这是抄写过来的,写得真的很好很好,是我看过关于GC方面讲解最清楚明白的一篇.原文地址是:https://www.zhihu.com/question/21539353

  4. C++引用计数设计与分析(解决垃圾回收问题)

    1.引言 上一篇博文讲到https://www.cnblogs.com/zhaoyixiang/p/12116203.html 我们了解到我们在浅拷贝时对带指针的对象进行拷贝会出现内存泄漏,那C++是 ...

  5. Objective-C内存管理之引用计数

    初学者在学习Objective-c的时候,很容易在内存管理这一部分陷入混乱状态,很大一部分原因是没有弄清楚引用计数的原理,搞不明白对象的引用数量,这样就当然无法彻底释放对象的内存了,苹果官方文档在内存 ...

  6. 恒生UFX接口引用计数心得

    本文介绍在基于恒生T2SDK基础上开发对接UFX柜台时,有关引用计数的一些心得体会. 下面以配置接口和连接接口为例子来介绍,下面是文档介绍: 创建配置接口说明: 3.1.2 创建配置接口(NewCon ...

  7. obj-c编程11:内存管理和ARC(自动引用计数)

    乖乖隆地洞,这篇文章内容可是不得了,内存管理哦!首先,这个要是搞不明白,你就等着进程莫名其妙的挂死,或是疯狂申请内存却不释放,结果被OS杀死,不管是"自杀"还是"他杀&q ...

  8. ZT Android的引用计数(强弱指针)技术及一些问题

    Android的引用计数(强弱指针)技术及一些问题 分类: Android 2013-06-07 18:25 844人阅读 评论(4) 收藏 举报 目录(?)[+] Android C++框架层的引用 ...

  9. std::shared_ptr 和 std::weak_ptr的用法以及引用计数的循环引用问题

    在std::shared_ptr被引入之前,C++标准库中实现的用于管理资源的智能指针只有std::auto_ptr一个而已.std::auto_ptr的作用非常有限,因为它存在被管理资源的所有权转移 ...

  10. 2. 引用计数法(Reference Counting)

    1960年,George E. Collins 在论文中发布了引用计数的GC算法. 引用计数法意如了一个概念,那就是"计数器",计数器表示的是对象的人气指数, 也就是有多少程序引用 ...

随机推荐

  1. Boring Game

    参考:https://blog.csdn.net/qq_45458915/article/details/107804348 模拟题 给出 n 张叠在一起的纸,现在将其连续从左向右折叠 k 次,再从上 ...

  2. 关于布尔类型的变量不要加 is 前缀,被网友们吐槽了,特来完善下

    开心一刻 一老农养猪,母的,怎么配也怀不上小猪,于是找兽医兽医来到他家看了猪一眼说:不行就人工授精吧老农绕着猪走了三圈,点燃一根烟,貌似下了很大决心,说到:行倒是行,就怕生下来像我 被网友吐槽 都说了 ...

  3. cmd怎么进入d盘某个文件下面

    1.打开命令提示符 首先,我们需要打开命令提示符.可以通过以下几种方式来打开Cmd: 1. 使用快捷键:按下Win + R键,在运行对话框中输入"cmd"并点击"确定&q ...

  4. 信而泰ALPS 用户管理——网络测试仪实操

    本文介绍了如何在ALPS平台上Step-By-Step进行用户管理 用户管理介绍 设备在出厂时,提供了一个默认管理员账号,该账号为admin/admin.管理员账号除了可用于测试之外,还具有用户管理权 ...

  5. 如何使用测试仪进行400G交换机性能测试

    一.400G以太网概述 400G以太网或400 Gigabit Ethernet (400GbE) 由 IEEE P802.3bs Task Force 于 2017 年开发,它使用与100 Giga ...

  6. Renix_端口迁移及修改 IP 地址——网络测试仪实操

    ​1.端口迁移功能概述 端口迁移功能允许用户将一个端口的配置迁移到另一个物理端口上. 2.端口迁移步骤如下: 2.1打开端口迁移向导: 在导航树,右键点击端口或者一组端口,然后从右键菜单选择" ...

  7. CentOS 8 安装Docker 报错requires container-selinux >= 2:2.x

    什么是 Docker 简单来说,Docker 是一个开源的容器化平台,它可以让你:把应用程序和它所有的依赖打包到一个"容器"中运行. 在传统部署中,你可能遇到这样的问题: &quo ...

  8. 我一个写Java的,怎么就开始玩K8s和Jenkins了?!

    前几天接到一个新任务,要求把以前部署在私有服务器上的项目,全都搬到云端去部署.之前的发布流程其实挺简单的,都是在本地打包好,然后通过文件传输把打好的jar包或者前端编译好的文件夹,直接替换到服务器上. ...

  9. git 本地协议、http、ssh、git协议优缺点总结对比

    之前一直使用的是git的http协议来推拉代码,新公司使用的是git协议,好奇这两种的区别,科普了一下,https://cloud.tencent.com/developer/article/1347 ...

  10. 解码C语言基础

    main函数-程序的入口 主函数有且只有一个 main无参形式 /* 函数名:main 函数参数:无 函数返回值: 返回0:表示函数正常退出 返回非0:表示函数异常退出 */ int main(voi ...