【Java】垃圾回收学习笔记(一):Root Search 根可达算法+垃圾回收的起点

文章目录

  • 1. 引用计数法
      • 优点
      • 缺点
  • 2. 可达性分析 Root Search
    • 2.1 那些对象是GC Roots
    • 2.2 引用的分类
    • 2.3 回收方法区
  • 3. 实现细节
    • 3.1 GC的起点:节点枚举
      • OopMap:帮助高效的根节点枚举
    • 3.2 何时开始GC:安全点与安全区域
      • 如何选取安全点
      • 如何让程序进入安全点
    • 3.3 程序不执行时的安全点:安全区域
  • Reference

最近上班地铁上偶尔看看书,周末有空理一下,做个笔记。
下面说说GC过程中如何判断对象是否存活。

1. 引用计数法

用于微软COM(Component Object Model)计数、Python语言等,进行内存管理。原理就是在对象中添加一个引用计数器:

  • 每当有地方引用他时,计数器加一;
  • 引用失效时,计数器减一;
  • 计数器为零时,对象就是不可能再被使用的。

优点

原理简单,判断效率高

缺点

单纯的引用计数很难解决对象间的相互循环引用问题,需要考虑很多额外情况

另外,Java虚拟机并不用引用计数来判断对象是否存活

2. 可达性分析 Root Search

Java、C#等主流商用程序语言凑采用可达性分析(Reachability Analysis)算法判定对象是否存活:

  1. 枚举一系列对象作为GC Roots
  2. 从GC Roots出发,搜索引用链,某个对象不可达时,则该对象判定为不可能再被使用(死亡)

在这里插入图片描述

2.1 那些对象是GC Roots

Java中,可作为GC Roots的对象包括:

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象,也就各个线程调用的对象;
  • 方法区中,类静态属性引用的对象;
  • 方法区中,常量引用的对象,比如字符串常量池中的引用;
  • 本地方法栈(Native方法)引用的对象;
  • JVM内部的引用,比如
    • 基本数据类型(float、double、int、long、byte、char、boolean)对应的Class对象
    • 常驻的异常对象(NullPointException、OutOfMemoryError)
    • 类加载器(BootstrapClassLoader、ExtensionClassLoader、AppClassLoaderfab)等等;
  • synchronized关键字持有的锁对象(一般是static对象,或者是当前类的Class对象);
  • 反应JVM内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等

在分代回收和局部回收过程中,可能会有临时对象加入GC Roots集合,来解决跨代引用等问题。

2.2 引用的分类

JDK1.2之后,Java扩充了引用的定义,不同引用在GC时的行为有所差异:

  • 强引用(Strongly Reference):在代码中通过Object o = new Object() 形势产生的引用关系。只要强引用存在,GC就不会回收被引用对象(哪怕OOM)。

  • 软引用(Soft Reference):通过SoftReference 类实现的引用。系统内存发生内存溢出前,会将软引用对象列入回收范围进行回收,如果回收后还没有足够内存,就抛出OOM。

  • 弱引用(Weak Reference):通过WeakReference 类实现的引用。无论内存是否足够,弱引用对象都会被GC。

  • 虚引用(Phantom Reference):通过PhantomReference 类实现的引用。虚引用无法对对象实际的生存时间造成影响,也不能通过虚引用来获得对象实例。虚引用的作用就是追踪对象的GC信息,在被回收时加入到关联的引用队列,可以得到一个通知或做些其他事。

    import java.lang.ref.PhantomReference;
    import java.lang.ref.ReferenceQueue;
    public class PhantomReferenceExample {public static void main(String[] args) {Object obj = new Object();ReferenceQueue<Object> queue = new ReferenceQueue<>();PhantomReference<Object> phantomRef = new PhantomReference<>(obj, queue);// 执行对象的清理操作Thread cleanupThread = new Thread(() -> {try {while (true) {PhantomReference<?> reference = (PhantomReference<?>) queue.remove();// 执行清理操作,比如释放资源System.out.println("Cleanup: " + reference);}} catch (InterruptedException e) {e.printStackTrace();}});cleanupThread.setDaemon(true);cleanupThread.start();obj = null; // 取消强引用System.gc(); // 手动触发垃圾回收// 在这里可以进行一些其他操作}
    }
    

    根可达算法中判定为不可达的对象,可以在finallize()方法中重新增加引用关联来复活(只能复活一次,try…finally也行)

2.3 回收方法区

《Java虚拟机规范》:可以不要求虚拟机在方法区中实现垃圾回收(比如JDK11 的ZGC收集器就不支持类卸载)。因为方法区回收的性价比通常较低。

方法区允许(不是必须)回收的对象一般是废弃的常量不再使用的类

  • 废弃的常量:类似堆中的对象,即没引用的常量。比如常量池中有个字符串对象,值为“java”,其回收条件为
    • 没用其他任何对象引用“java”常量;
    • 虚拟机中没有“java”字面量的引用。
  • 不再被使用的类需要同时满足三个条件才会允许(不是必须)被回收(即类卸载):
    • 该类的所有实例都已经被回收(堆中不存在该类及其子类的实例);
    • 加载该类的类加载器已经被回收;
    • 该类对应的Class对象也没被引用(即不能通过反射访问该类的method跟filed)。

Hotspot虚拟机提供了-Xnoclassgc参数进行类卸载控制,还有一系列参数查看类可查看类加载和类卸载信息。

在动态代理大量使用的场景(大量使用反射、CGLib等),或者需频繁自定义类加载器等场景中,通常需要JVM具备类卸载能力,以保证生成的代理类对象不会对方法区造成过大压力。

3. 实现细节

简单来说就是,在安全点进行GC roots枚举,然后开始可达性分析(比如三色标记),标记完后由垃圾收集器采用特定的回收算法进行内存回收。

3.1 GC的起点:节点枚举

由于用户进程运行过程中,根节点集合的对象引用关系会不断变化,为了保证一致性,在根节点枚举过程中需要停顿所有用户线程,不可避免地面临“Stop The World”(但由GC Roots查找引用链的过程已经可以与用户线程并发了)

OopMap:帮助高效的根节点枚举

实际上,停止用户线程进行根节点枚举的时候,不需要一个不漏地检查所有执行的上下文和全局引用。HotSpot使用了OopMap()来直接得到引用信息,在类加载完成后,HotSpot会计算对象内某个偏移量上时什么类型的数据,也会在即时编译的过程中记录栈帧和寄存器里的引用位置。

3.2 何时开始GC:安全点与安全区域

OopMap可以帮助JVM快速完成根节点枚举。但是程序不同线程是按一条条指令执行的,许多指令都可能导致对象引用关系的变化,如果为每条指令都生产OopMap会消耗大量的内存空间,因此可以在“特定位置”生产OopMap。前面有提到,根节点枚举会有STW来避免对象引用关系的变化,现在的问题就是:

在何时让这些线程停止?(即在什么时候生成OopMap/开始GC)

在HotSpot中,这个“特殊位置”就是安全点(Safe Point),用户程序执行时,强制要求执行到安全点后才能暂停下来,开始GC。

再明确一下,安全点就是GC的起点,程序需要GC时,所有线程需要跑到对应的安全点,安全点处有对应的OopMap,可以帮助虚拟机进高效地搜索GC root集合,然后开始GC流程。

如何选取安全点

安全点选的太少,会让收集器等待时间太久;安全点选的太频繁,会增大运行时的内存负荷(每个安全点都会有对应的OopMap)。

安全点的选取标准:**能否让程序长时间执行。**即指令序列的复用,比如方法调用、循环跳转、异常跳转等就会产生安全点。

为什么安全点需要让程序一直跑/为什么安全点要考虑指令序列的复用?

可以理解为,在安全点的程序指令运行时间较长(复用较多),需存活的对象相对重复,不能让过多的死对象占用内存,因此适合作为GC的起点。

如何让程序进入安全点

即如何让GC发生时,让所有线程都跑到最近的安全点。一般包括两种方案:

  • 抢先式中断:GC发生时,中断所有线程,如果有线程没到安全点,就恢复执行(现在几乎没有虚拟机用抢先式中断);
  • 主动式中断:需要中断线程时,垃圾收集器设置一个标志位,各个线程不断主动轮询该标志位,一旦标志位位true,线程在自己最近的安全点刮起。
    • 轮询的标志位与安全点重合,且需要包括创建对象等需要在堆上分配内存的地方,避免没有足够内存分配新对象(是否有必要GC)。

3.3 程序不执行时的安全点:安全区域

如果程序当前没分配执行时间(Sleep或Block状态),就走不到安全点,然后挂起,等待开始GC。因此可以把这些没分配执行时间的位置作为安全区域(Safe Region)。与安全点类似,在安全区域中,引用关系不会发生变化。

  • 当用户线程执行到安全区域时,会标识自己进入安全区域,当虚拟机需要GC时就不用管这些标识进入安全区域的线程。
  • 当线程要离开安全区域时,需检查根节点枚举是否完成根节点枚举(或其他STW阶段),如果完成则继续执行,如果未完成则一直等待知道收到完成的信号。

Reference

《深入理解java虚拟机:JVM高级特性与最佳时间(第3版)》 周志明
ps:虚引用的例子是也是网上找的,但原文找不到了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/868055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

rocketmq-console可视化界面功能说明

rocketmq-console可视化界面功能说明 登录界面OPS(运维)Dashboard(驾驶舱)Cluster(集群)Topic(主题)Consumer(消费者)Producer(生产者)Message(消息)MessageTrace(消息轨迹) rocketmq-console是rocketmq的一款可视化工具&#xff0c;提供了mq的使用详情等功能。 本章针对于rock…

玫瑰千层烤饼:味蕾的芬芳盛宴

在美食的缤纷世界里&#xff0c;有一种独特的存在&#xff0c;它融合了玫瑰的芬芳与烤饼的酥脆&#xff0c;那便是令人陶醉的甘肃美食玫瑰千层烤饼。食家巷玫瑰千层烤饼&#xff0c;宛如一件精心雕琢的艺术品。每一层薄如纸张的面皮&#xff0c;都承载着制作者的细腻与用心。层…

【qt】TCP 服务端怎么收到信息?

上一节,我已经讲了,TCP的监听,是基于上一节的,不知道的可以看看. 当我们的TCP 服务器 有 客户端请求连接的时候,会发出一个信号newConnection(). 在TCP服务端与客户端的通信中,我们需要使用到套接字 QTcpSocket类. 套接字相当于是网络通信的接口,服务段和客户端都要通过它进行通…

Gitlab Fork Workflow(协作工作流)

Gitlab Fork WorkFlow&#xff08;协作工作流&#xff09; Fork WorkFlow用于团队间的协作开发。在开发过程中&#xff0c;我们都需要将最新修改的代码合并到代码库上&#xff0c;在代码合并之前&#xff0c;为了保证代码符合上传要求&#xff08;符合需求、代码规范等&#xf…

如何在应用运行时定期监控内存使用情况

如何在应用运行时定期监控内存使用情况 在 iOS 应用开发中&#xff0c;实时监控内存使用情况对于优化性能和排查内存泄漏等问题非常重要。本文将介绍如何在应用运行时定期监控内存使用情况&#xff0c;使用 Swift 编写代码并结合必要的工具和库。 1. 创建桥接头文件 首先&…

vue学习笔记之组件传值

说起组件传值&#xff0c;首先要介绍再vue中什么是组件。 组件&#xff08;Component&#xff09;&#xff0c;是vue中很强大的一个功能&#xff0c;可以将一些可重用的代码进行重用。所有的vue组件同时也是vue实例&#xff0c;可以接受使用相同的选项对象和提供相同的生命周期…

集合复习(java)

文章目录 Collection 接口Collection结构图Collection接口中的方法Iterator 与 Iterable 接口Collection集合遍历方式迭代器遍历增强 for 遍历 List&#xff08;线性表&#xff09;List特有方法ArrayList&#xff08;可变数组&#xff09;ArrayList 底层原理ArrayList 底层原理…

JAVA集合框架、CAS、AQS

目录 一、java 的集合框架有哪些? 二、说-下 ArrayList 和 LinkedList? 三、HashSet和TreeSet的区别? 四、HashMap 的数据结构是什么? 五、CAS机制 六、AQS理解 一、java 的集合框架有哪些? Collection 是 Java 集合框架中的一个根接口&#xff0c;位于 java.util 包中。它…

【SVN的使用-源代码管理工具-命令行的使用 Objective-C语言】

一、接下来,我们来说一个终端的命令行的使用, 1.我们说,你的电脑里边呢,有终端, 在Mac里边,你想新建一个txt,应该怎么写,对,打开文本编辑, 打开这个东西,写点儿东西,然后保存一下,保存的时候,你还要去选择格式, 现在,如果我们用命令行,可以更方便一些, 2.首…

【基于R语言群体遗传学】-10-适应性与正选择

在之前的博客中&#xff0c;我们学习了哈代温伯格模型&#xff0c;学习了Fisher模型&#xff0c;学习了遗传漂变与变异的模型&#xff0c;没有看过之前内容的朋友可以先看一下之前的文章&#xff1a; 群体遗传学_tRNA做科研的博客-CSDN博客 一些新名词 &#xff08;1&#xf…

MySQL 中的 DDL、DML、DQL 和 DCL

文章目录 1. 数据定义语言&#xff08;DDL&#xff09;2. 数据操作语言&#xff08;DML&#xff09;3. 数据查询语言&#xff08;DQL&#xff09;4. 数据控制语言&#xff08;DCL&#xff09;总结 在 MySQL 数据库管理系统中&#xff0c;SQL 语句可以根据其功能分为不同的类别&…

RAG 案框架(Qanything、RAGFlow、FastGPT、智谱RAG)对比

各家的技术方案 有道的QAnything 亮点在&#xff1a;rerank RAGFLow 亮点在&#xff1a;数据处理index 智谱AI 亮点在文档解析、切片、query改写及recall模型的微调 FastGPT 优点&#xff1a;灵活性更高 下面分别按照模块比较各框架的却别 功能模块QAnythingRAGFLowFastG…

TP8/6 子域名绑定应用

原www.xxx.com/admin改为admincms.xxx.com config/app.php 官方文档&#xff1a;ThinkPHP官方手册

赋值运算符重载和const成员函数和 const函数

文章目录 1.运算符重载(1)(2)运算符重载的语法&#xff1a;(3)运算符重载的注意事项&#xff1a;(4)前置和后置重载区别 2.const成员函数3.取地址及const取地址操作符重载4.总结 1.运算符重载 (1) 我们知道内置类型(整形&#xff0c;字符型&#xff0c;浮点型…)可以进行一系…

2024-07-05 base SAS programming学习笔记9(variables)

1.在数据集增加累加变量值&#xff08;SUM&#xff09; 求和语句(SUM STATEMENT)&#xff1a;variableexpression variable是累积求和的变量名&#xff0c;为数值型&#xff0c;默认初始值为0&#xff1b;该variable值则会保留到一个观测 当expression有缺失值&#xff0c;在求…

【项目管理】常见的敏捷实践:Scrum框架

【项目管理】常见的敏捷实践&#xff1a;Scrum框架 精益、敏捷与Scrum框架Scrum框架实践Sprint&#xff08;冲刺&#xff09;Scrum角色Scrum工件Scrum会议 精益、敏捷与Scrum框架 敏捷与精益思想、看板、Scrum等概念的关系如下图所示&#xff1a; Lean 精益 Kanban 看板 Ag…

文件存储的方法一

文章目录 概念介绍实现方法示例代码 我们在上一章回中介绍了"如何实现本地存储"相关的内容&#xff0c;本章回中将介绍如何实现文件存储.闲话休提&#xff0c;让我们一起Talk Flutter吧。 概念介绍 我们在上一章回中介绍的本地存储只能存储dart语言中基本类型的数值…

机器学习训练之使用静态图加速

前言 MindSpore有两种运行模式&#xff1a;动态图模式和静态图模式。默认情况下是动态图模式&#xff0c;也可以手工切换为静态图模式。 动态图模式 动态图的特点是计算图的构建和计算同时发生&#xff0c;符合Python的解释执行方式。在调试模型时较为方便&#xff0c;能够实…

开发者评测|操作系统智能助手OS Copilot

操作系统智能助手OS Copilot 文章目录 操作系统智能助手OS CopilotOS Copilot 是什么优势功能 操作步骤创建实验重置密码创建Access Key配置安全组安装 os-copilot环境变量配置功能评测命令行模式多轮交互模式 OS Copilot 产品体验评测反馈OS Copilot 产品功能评测反馈 参考文档…

做测试/爬虫 selenium 元素定位 谷歌浏览器 插件推荐,提高元素定位效率

注:插件均在谷歌应用商店 下载 1.XPath Helper 插件 作用&#xff1a;用于Html中对目标字段或者属性值进行匹配 快捷启动&#xff1a;ctrl shift x 示例图如下&#xff1a; 2. ChroPath 插件 作用&#xff1a; 提高元素定位效率 启动&#xff1a;谷歌浏览器 按 F12 -&g…