0

0

什么是JVM的OopMap_精确式垃圾收集中的引用记录与安全点交互原理

P粉602998670

P粉602998670

发布时间:2026-03-15 13:28:03

|

169人浏览过

|

来源于php中文网

原创

OopMap是JVM静态生成的内存偏移标记,标识栈帧中对象引用位置;GC仅在安全点依据OopMap精确扫描引用,避免误标或漏标,其生成依赖编译器或解释器,与代码位置严格对齐。

什么是jvm的oopmap_精确式垃圾收集中的引用记录与安全点交互原理

什么是 OopMap,它在 GC 时怎么被用到

OopMap 不是类、也不是配置项,而是 JVM 在编译或解释执行时**静态生成的一组内存偏移标记**,用来告诉 GC:“这个栈帧里,从哪几个字节偏移开始,存的是对象引用(oop)”。GC 做精确式回收时,必须知道哪些位置存的是引用,否则没法判断对象是否还被持有。

它不运行时动态扫描,也不靠保守式猜测——所以叫“精确式”。但这也意味着:OopMap 必须和代码执行位置严格对齐。一旦指令指针停在两个 OopMap 记录之间,JVM 就不知道那块内存里存的是 int 还是 oop。

  • OopMap 只在安全点(safepoint)处生效;非安全点位置的栈帧即使有 OopMap,GC 也不会读取
  • HotSpot 中,OopMap 由 C1/C2 编译器在生成本地代码时插入,解释器则在每条字节码边界按需生成(通过 TemplateTableInterpreterMacroAssembler
  • 一个方法可能对应多个 OopMap(比如循环体前后、异常表入口等不同 PC 偏移),每个都绑定具体字节码索引

为什么必须配合安全点才能做精确 GC

因为 Java 线程随时可能被暂停,但不是任意时刻都能安全读取其栈内存。比如正在执行 mov rax, [rbx+8] 这条指令时,rbx 可能刚被赋值为临时整数、还没来得及存对象地址——此时若强行扫描栈,会把一个 int 当成 oop,导致本该回收的对象被错误保留(漏标)。

安全点就是 JVM 预先选定的、保证寄存器和栈状态“语义清晰”的少数位置。只有线程跑到这些点并主动挂起,GC 才能信任当前 OopMap 并扫描引用。

  • 常见安全点位置:方法返回前循环回边方法调用前抛异常时
  • Thread::check_safepoint() 是线程自己轮询的钩子,不是信号中断;所以如果一段代码既没方法调用、又没循环、还不分配对象(如纯计算大数组),就可能长时间不进安全点,造成 GC 停顿等待
  • 可通过 -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 观察哪些线程卡在哪

OopMap 和栈帧结构的关系容易被误解

OopMap 不描述整个栈帧布局,只记录“哪些栈槽(slot)或局部变量表索引位置当前存的是对象引用”。它不关心这个 slot 是局部变量、操作数栈顶,还是刚压入的临时值——只要那个内存单元此刻语义上是 oop,就得标记。

ChatDOC
ChatDOC

ChatDOC是一款基于chatgpt的文件阅读助手,可以快速从pdf中提取、定位和总结信息

下载

而且 OopMap 是“瞬时快照”,同一栈帧在不同 PC 处的 OopMap 可能完全不同。比如一个局部变量 obj 在方法开头是 null,OopMap 就不标记它;等执行到 obj = new Object() 后,对应 slot 就会被标记为 oop。

  • OopMap 中的偏移单位是“字宽”(通常 4 或 8 字节),不是字节码索引,也不是 Java 字段偏移
  • 解释器栈帧里,OopMap 直接映射到 interpreter_frame_local_at() 的索引;编译后代码则映射到 RBP 偏移或寄存器分配结果
  • 不要试图手动解析 OopMap 数据——它是 HotSpot 内部二进制格式,结构随 JVM 版本变化,OopMap::print_on() 是唯一可靠查看方式

调试 OopMap 相关问题的实际线索

真正出问题时,你不会看到 “OopMap error” 这种报错。它的问题都藏在 GC 行为异常里:比如 CMS 失败后 fallback 到 Serial GC、G1 混合回收迟迟不触发、或者 java.lang.OutOfMemoryError: Java heap space 伴随极低的存活对象比例——说明引用关系没被正确识别,大量对象被误判为可回收。

  • jhsdb jstack --pid <pid> 查看线程是否卡在 safepoint 等待,再结合 -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly 看热点方法有没有密集安全点
  • 如果某段 JNI 代码长期不返回,且 Java 层无调用,会导致该线程无法进入安全点——此时其他线程的 GC 停顿会被拖长,但日志里只显示 “No safepoint happened” 类似提示
  • 开启 -XX:+VerifyOopMaps(仅限 debug 版 JVM)会在每次 GC 前校验 OopMap 有效性,但会显著降低性能,仅用于定位疑似生成错误的场景

最麻烦的不是 OopMap 本身难懂,而是它和安全点、编译策略、JNI 调用三者耦合太紧——改一行 Java 代码,可能让 C2 把循环展开,从而删掉一个关键安全点;加一个 System.gc(),又可能让 JIT 放弃内联,多出一堆 OopMap。这种间接影响,很难单靠看文档定位。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门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语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

254

2023.09.22

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

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

1111

2024.03.01

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

493

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

382

2023.10.25

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1051

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

616

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

335

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

235

2025.08.29

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

69

2026.03.13

热门下载

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

精品课程

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

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