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

news2024/12/25 1:30:33

文章目录

  • 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.coloradmin.cn/o/1905931.html

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

相关文章

数据驱动的内容优化:Kompas.ai如何提升内容表现

在数字化营销时代&#xff0c;内容是企业与用户沟通的重要桥梁。然而&#xff0c;随着信息量的爆炸性增长&#xff0c;如何让内容在激烈的竞争中脱颖而出&#xff0c;成为每个营销人员面临的问题。数据驱动的内容优化策略&#xff0c;通过精准分析和科学决策&#xff0c;帮助品…

华为OD机试 - 员工派遣(Java 2024 D卷 200分)

华为OD机试 2024D卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;D卷C卷A卷B卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测…

基于字典学习的地震数据降噪(MATLAB R2021B)

稀疏表示基于研究者们提出了许多变换基函数的方法逐渐成型&#xff0c;比如小波域&#xff0c;曲波域&#xff0c;dreamlet 域等&#xff0c;其原理是利用地震信号在变换域内的稀疏性和可分离性以去除噪声。继 Donoho发表非线性去噪方法-小波阈值萎缩方法&#xff0c;在后续的研…

Swift 中 map 和 flatMap 的区别 (入门版)

在 Swift 中&#xff0c;map 和 flatMap 是用于处理集合类型&#xff08;如数组、字典、集合等&#xff09;的两个重要方法。尽管它们看起来相似&#xff0c;但它们在处理集合中的元素和结果时有着不同的行为。 map 方法 map 方法会对集合中的每一个元素应用一个变换&#xff…

C++ 面试宝典之:空类大小究竟是不是 0?

以下内容为本人的学习笔记&#xff0c;如需要转载&#xff0c;请声明原文链接 微信公众号「ENG八戒」https://mp.weixin.qq.com/s/pD4bIjX2kDzo8gbYRPktPQ 首先&#xff0c;空类是什么&#xff1f;空类指的是不包含任何数据成员的类&#xff0c;但可能包含方法成员。 实例化时…

Redis常用命令——Set、Zset篇

文章目录 一、Set相关命令操作 SADD SMEMBERS SISMEMBER SCARD SPOP SMOVE SREM SINTER 与 SINTERSTORE SUNION 与 SUNIONSTORE SDIFF 与 SDIFFSTORE Set命令小结 二、Zset 相关命令操作 ZADD ZCARD ZCOUNT ZRANGE ZREVRANGE ZPOPMAX BZPOPMAX ZPOPMIN 与 BZPOPMIN ZRANK 与 …

AI Earth ——开发者模式案例10:基于 CNN 的 AI 分类模型开发

基于 CNN 的 AI 分类模型开发 本案例主要介绍如何快速利用 AIE Python SDK 创建机器学习建模流程。我们主要使用到 Python SDK的Machine Learning Proxy 模块(下文简称 AieMlProxy )。该模块涵盖了一系列用户与训练集群之间的交互接口,包括:鉴权、数据加载、训练任务提交、…

OpenCV杂记(4):OpenCV之色彩映射(伪彩applyColorMap)

1. 简述 我们在开发基于热成像&#xff08;红外&#xff09;或者做深度估计应用时&#xff0c;为了便于直观的观察&#xff0c;常常将检测结果进行色彩上的映射&#xff0c;这样便可以很直观的看出哪里温度高&#xff0c;哪里温度低&#xff0c;或者哪里深度更深或更浅。 我们将…

【STM32项目】基于Stm32搞怪盒子的设计(完整工程资料)

基于stm32搞怪的盒子设计 前言&#xff1a; 最近我看到一个极具创意的搞怪盒子&#xff0c;设计得相当有意思。作为一个热衷于电子DIY的狂热爱好者&#xff0c;怎能错过这样一个有趣的项目呢&#xff1f;于是&#xff0c;我决定亲自动手&#xff0c;设计一个属于自己的、独一无…

代码随想录——单调递增的数字(Leetcode738)

题目链接 贪心 class Solution {public int monotoneIncreasingDigits(int n) {char[] digits String.valueOf(n).toCharArray();int flag digits.length;for (int i digits.length - 1; i > 0; i--) {if (digits[i] < digits[i - 1]) {flag i;digits[i - 1]--;}}…

KVM把新添加的磁盘扩容到根目录

1、对新增的磁盘进行分区&#xff08;注&#xff1a;可省略&#xff09; PS&#xff1a;使用fdisk或gdisk&#xff08;大于2T时使用&#xff09;对新增磁盘进行分区。 [rootkvm-clinet ~]# fdisk/dev/sdb Welcome to fdisk (util‐linux 2.23.2).4 Changes will remain in …

GISSERVER 管理器发布切片服务

GISSERVER 管理器 1.0(私有化地图离线部署)可以为您发布切片服务&#xff0c;切片服务的概念可以见我以前的文章&#xff1a;如何生成像谷歌高德一样的切片地图。除了我们自己制作的切片外&#xff0c;我们最常见的是利用各类地图下载器下载的在线地图的切片。见&#xff1a;栅…

Qt文档阅读笔记-Queued Custom Type Example

此篇展示了使用Qt编写多线程程序。 概述 此案例创建一Block类&#xff0c;用于存储数据&#xff0c;并且在元对象系统中注册后&#xff0c;在多线程中进行信号与槽函数的连接中充当参数。 Block类 在元对象系统中&#xff0c;注册类&#xff0c;需要类在public部分提供默认构…

56、最近邻向量量化(LVQ) 网络训练对输入向量进行分类

1、LVQ 网络训练对输入向量进行分类简介 1&#xff09;简介 LVQ&#xff08;最近邻向量量化&#xff09;是一种简单而有效的神经网络模型&#xff0c;用于对输入向量进行分类。LVQ网络通过学习一组原型向量&#xff08;也称为代码矢量或参考向量&#xff09;&#xff0c;来表…

如何恢复已删除的音频文件

设备中文件被意外删除并不是什么新鲜事。但是&#xff0c;如果文件是你最喜欢的 MP3 歌曲&#xff0c;那就太令人沮丧了。但你知道吗&#xff0c;有一种方法可以从 Windows 机器中恢复已删除的音乐文件。尝试奇客数据恢复并检索已删除的音频文件。虽然产品名称听起来不像可以帮…

HTML5使用<blockquote>标签:段落缩进

使用<blockquote>标签可以实现页面文字的段落缩进。这一标签也是每使用一次&#xff0c;段落就缩进一次&#xff0c;并且可以嵌套使用&#xff0c;以达到不同的缩进效果。语法如下&#xff1a; <blockquote>文字</blockquote> 【实例】使用<blockquote&…

DC/AC电源模块的节能特点与环保优势

BOSHIDA DC/AC电源模块的节能特点与环保优势 在过去的几十年里&#xff0c;人们对电力的需求不断增加&#xff0c;这导致了电力系统的扩展和增加&#xff0c;为了满足这些需求&#xff0c;传统的交流&#xff08;AC&#xff09;电源系统在全球范围内广泛使用。然而&#xff0c…

8.1 栅格图层符号化整体说明

文章目录 前言栅格图层符号化总结 前言 地图制图是QGIS的优势所在&#xff0c;QGIS包含完整的地图制图功能&#xff0c;如标注与注记、符号化与地图综合等多种功能。 在地图制图过程中&#xff0c;必须经过符号化和地图综合两个最基本的操作。符号化&#xff08;Symbolization&…

《Nature》文章:ChatGPT帮助我学术写作的三种方式

图片翻译 ** 文章内容** 忏悔时间&#xff1a;我使用生成式人工智能&#xff08;AI&#xff09;。尽管在学术界关于聊天机器人是积极力量还是消极力量的争论不休&#xff0c;但我几乎每天都使用这些工具来完善我所写论文中的措辞&#xff0c;并寻求对我被要求评估的工作进行替…

MySQL性能优化 一、系统配置优化

数据库优化纬度有四个&#xff1a; 硬件升级、系统配置、表结构设计、SQL语句及索引。 优化选择&#xff1a; 优化成本&#xff1a;硬件升级 > 系统配置 > 表结构设计 > SQL语句及索引优化效果&#xff1a;硬件升级 < 系统配置 < 标结果设计 < SQL语句及索…