0

0

Java中哪些对象可以作为GC Roots_可达性分析算法深度解析

P粉602998670

P粉602998670

发布时间:2026-03-18 13:18:01

|

856人浏览过

|

来源于php中文网

原创

GC Roots是JVM判断对象存活的起点,包括Java线程对象、栈帧局部变量、已加载Class对象、JNI全局引用及JVM内部关键对象;Reference子类实例自身是Roots,但其referent不是。

java中哪些对象可以作为gc roots_可达性分析算法深度解析

哪些对象能当 GC Roots?不是“谁重要”而是“谁不能被回收”

GC Roots 是 JVM 判断对象是否存活的起点,不是靠“身份”决定的,而是看它是否天然具备强引用锚点。只要这个对象在当前时刻必须存在、无法被垃圾回收器主动清理,它就可能成为 GC Root。

常见误区是以为“new 出来的对象”或“static 字段”自动就是 Roots——其实 static 字段指向的对象只是**通过 Roots 可达**,字段本身(即类的静态变量槽)才是 Roots;而 new 出来的对象绝大多数时候反而是被 Roots 引用的叶子节点。

  • JavaThread 对象本身(不是线程栈帧里的局部变量)、所有正在执行的 Java 线程的栈帧中的局部变量表项(LocalVariableTable
  • 已加载的 Class 对象(由 BootstrapClassLoaderPlatformClassLoaderAppClassLoader 加载的类本身)
  • JNI 方法栈中引用的 Java 对象(JNIEnv* 持有的全局/弱全局引用)
  • JVM 内部关键对象:如系统类加载器、常量池中指向类/字符串的引用、java.lang.ref.Reference 子类实例(但注意:Reference 本身是 Roots,其 referent 字段指向的对象不是)

为什么 finalizer 队列里的对象不算 GC Roots?

这是个高频误解:有人看到 Finalizer 类里有个 queue 静态字段,就以为队列里的对象是 Roots。实际上,Finalizer 实例本身是 Roots(因为它是 java.lang.ref.Finalizer 类的静态字段值),但它持有的 referent 是待终结对象——这个 referent 正处于“不可达但尚未 finalize”的中间状态,JVM 明确不把它当作 Roots,否则就永远无法回收了。

  • 一旦对象进入 Finalizer 队列,它已从常规引用链断开,仅靠 Finalizer 实例维持弱关联
  • 如果把 referent 当作 Roots,那所有重写了 finalize() 的对象都永远活在堆里
  • JDK 9+ 已废弃 finalize()Finalizer 类本身也被标记为 @Deprecated(since="9", forRemoval=true)

WeakReference / SoftReference / PhantomReference 怎么影响可达性判定?

它们不是改变 GC Roots,而是改变“从 Roots 出发的引用强度”。JVM 在做可达性分析时,会按引用类型分阶段扫描:先走强引用链,再根据策略决定是否跟进软/弱/虚引用。

立即学习Java免费学习笔记(深入)”;

Buildt.ai
Buildt.ai

AI驱动的软件开发平台,可以自动生成代码片段、代码分析及其他自动化任务

下载
  • WeakReference:GC 时只要发现没有强/软引用链可达,就直接清空 referent 并入队,不等下次 GC
  • SoftReference:只在内存不足(HeapSpace 回收后仍不够)时才清空,具体策略由 HotSpotLRUclock 算法实现,与 -XX:SoftRefLRUPolicyMSPerMB 参数相关
  • PhantomReferencereferent 被回收后才入队,且 get() 永远返回 null;它本身必须配合 ReferenceQueue 使用,否则毫无意义

注意:Reference 子类实例自身是 GC Roots(因为是 ReferenceQueue 或静态字段持有),但它们的 referent 字段不是。

本地方法栈和 JNI 引用容易漏掉哪些 Roots?

很多 NIO 直接内存泄漏或 OutOfMemoryError: Direct buffer memory 问题,根源在于忽略了 JNI 全局引用(jobject)也是 GC Roots。

  • C/C++ 代码调用 NewGlobalRef() 创建的引用,必须配对调用 DeleteGlobalRef(),否则该引用永远有效,其指向的 Java 对象永不回收
  • NewWeakGlobalRef() 创建的是弱引用,不阻止回收,但需注意:它在 GC 后可能变成 NULL,使用前必须判空
  • JNI 方法退出时,局部引用(LocalRef)自动释放,但若在循环中频繁创建(比如遍历数组每个元素调用 NewLocalRef),可能触发 PushLocalFrame/PopLocalFrame 达到上限,报错 java.lang.OutOfMemoryError: Cannot allocate new local reference

真正难排查的是那些跨线程传递的 JNI 引用——比如一个后台 C 线程持有了 Java 对象的 GlobalRef,但 Java 层早已认为该对象该死了。这种跨语言生命周期管理,没有自动机制,全靠开发者手动对齐。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

256

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

1154

2024.03.01

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1571

2023.10.24

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1571

2023.10.24

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

761

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1571

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

652

2023.11.24

Python WebSocket实时通信与异步服务开发实践
Python WebSocket实时通信与异步服务开发实践

本专题聚焦 Python 在实时通信场景中的开发实践,系统讲解 WebSocket 协议原理、长连接管理、消息推送机制以及异步服务架构设计。内容包括客户端与服务端通信实现、连接稳定性优化、消息队列集成及高并发处理策略。通过完整案例,帮助开发者构建高效稳定的实时通信系统,适用于聊天应用、实时数据推送等场景。

3

2026.03.18

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4.5万人学习

C# 教程
C# 教程

共94课时 | 11.5万人学习

Java 教程
Java 教程

共578课时 | 83.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号