前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OopMap理论篇

OopMap理论篇

原创
作者头像
子牙老师
发布2022-04-22 14:22:48
6990
发布2022-04-22 14:22:48
举报
文章被收录于专栏:手写JVM专栏

哈喽,我是子牙。十余年技术生涯,一路披荆斩棘从技术小白到技术总监到JVM专家到创业。技术栈如汇编、C语言、C++、Windows内核、Linux内核。特别喜欢研究虚拟机底层实现,对JVM有深入研究。分享的文章偏硬核,很硬的那种。

手撸过JVM、内存池、垃圾回收算法、synchronized、线程池、NIO…

最近正在写三色标记算法,准备实现OopMap了,把JVM的OopMap机制认真梳理了下。为什么要梳理,而不是基于对理论的理解去写?为了尽量跟Hotspot源码保持一致。东西有点多,怕后面忘记,写几篇文章记录下。

国籍惯例,百度了下OopMap相关的文章,嗯,基本都是从周志明的书《深入理解Java虚拟机》摘录出来的,见怪不怪了。因为本人熟读Hotspot源码,所以本人的文章除了会把OopMap理论与GC、运行时串起来,还会加入我的独特理解,及Hotspot源码证明。

大概会讲这些:

1、垃圾收集器各个阶段与STW、安全点、OopMap之间的关系

2、识别数据类型的三种算法

3、GC如何找到JNI线程创建的对象

4、哪些场景会生成OopMap记录

5、生成OopMap记录的几个重要方法

6、OopMap记录如何理解

OopMap

一看到Oop,大家是不是条件反射:面向对象?面向对象map?好像说不通啊!

这里的Oop是普通对象指针的意思:ordinary object pointer。这里的map也不是指对应的数据结构是map,而是地图的意思。所以翻译过来就是普通对象指针地图,与现实很贴切。

何谓普通对象指针?就是指一个Java对象,在JVM中,或者Hotspot源码层面,对应一个C++实例。在Java层面,我们叫Java对象,在JVM层面,我们叫oop。与之对应的就是klass,就是一个Java类在JVM中对应的C++实例。还有handle,这个是一整套机制,后面讲到GC处理JNI线程创建的对象时细讲。

oop-klass-handle机制,是JVM的基石,对于理解Hotspot源码,极其重要。

关于OopMap,很多人对它的基础理解都错了,自然看一些文章,怎么看都看不懂。

聊聊GC

语言学习最大的门槛是语言本身,比如C语言的指针。相对来说,高级语言如Java、Python、PHP等,语言本身难度较低,所以学起来比较容易。你觉得生活轻松,是因为有人替你承担了大多数,计算机的世界也一样。高级语言学起来之所以轻松,是因为高级语言的运行环境,即虚拟机,为你承担了大多数。今天就谈谈其中之一的GC。

GC的目的很简单:自动回收内存。再精确点说,高效回收不被使用的对象占用的内存。为了这一目标,GC经历了串行回收到并行回收到并发回收阶段。并发阶段好像已经是终点,于是开始在内存设计上做文章,经历了从一个大堆到1:1堆到1:1:8堆到region堆。好像基于region块的堆又是终点了。下一代GC将会是什么样呢?我也不知道,但我保持期待。

GC一般是找到还在使用的对象,打上标记,清理那些没有打标记的对象。那GC怎么找到还在使用的对象呢?分两个阶段:先找到活动对象,再基于活动对象引用链一层一层往下找。

活动对象在哪里:

1、Java线程栈中

2、JNI线程栈中

3、寄存器中

4、可能我没想到的情况

栈与寄存器都是无状态的,言外之意就是说GC时是不知道寄存器中或栈中那一串数字到底是oop还是就是数字。

那怎么办呢?JVM采用的是准确式GC,言外之意就是说能准确的知道哪些区域存储的是oop。怎么做到的呢?就是通过引入OopMap。其实就是一种空间换时间的方式,在GC来临之前,根据栈图及寄存器生成OopMap记录。

生成OopMap记录,必然带来额外的开销,所以不适合持续进行。就像一个商店盘点第二天需要进的货,不是卖出一件盘点一下,而是打烊前完整得盘点。程序世界也一样。那这个何时的时机是什么时候呢?就是GC之前,安全点激活,线程进入安全点的时候。关于安全点,STW理解得不太好的小伙伴,可以看我另外一篇文章

下一个问题:GC是怎么基于根对象一层一层往下找的?言外之意是说GC是怎么知道对象哪些属性是引用?这就要说到另一个数据结构:OopMapBlock。这个本篇文章就不展开讲了,后面有机会会写文章单独讲,这里大家知道有这样一个东西的存在,做了这个事情,就可以了。学习,有的时候,需要囫囵吞枣。

总结一下,程序平时运行不会生成OopMap,只有在GC前才会生成OopMap。GC前会激活安全点,所有线程都会进入安全点,即STW。JVM根据平时运行形成的栈图创建OopMap记录,供GC时遍历根对象使用。这句话就是GC、STW、安全点、OopMap的完整关系。解释执行是这样运作的,编译执行还不太一样,后面讲。

这里有个新名词:栈图。栈图底层实现后面有空讲,大家只需要知道它是干这个事的就行:它用来标识局部变量表或操作数栈中每个slot存储的数据类型。

是不是有些小伙伴想到了记忆集及卡表?这里不展开讲,感兴趣的小伙伴可以看我之前写的一篇文章

准确式GC

前面一段好干有木有?来点不干的舒缓下情绪,因为后面还有更干的 ^_^

根据识别数据类型的准确度划分,有这三种算法:

1、保守式GC:即不记录数据的类型,GC时全栈扫描,但是就算是全栈扫描,怎么区分是oop还是数字呢?进行边界比对,比如堆的起始位置是top,结束位置是bottom,在这中间的就是oop。很明显,这个算法实现起来很简单,但是太low了,效率也很低。

2、半保守式GC:根对象不记录类型,根对象派生出来的对象记录数据类型。比如根对象A的地址存储在栈中,没有标记类型,找出所有根对象需要全栈扫描,但是A对象的属性B对象,在类A的元信息中有记录,可以顺藤摸瓜找到,减少程序憨憨遍历时间。

3、准确式GC:不管是根对象,还是派生对象,都标记类型。JVM中引入外部数据结构OopMap+OopMapBlock实现了该算法。

采用准确式GC思路,本质就是说,程序平时运行多花费一点点时间记录数据,帮助GC时减少延时,是值得的。

到这里就把OopMap相关的理论知识讲完了。当然,Hotspot源码很庞大,关于OopMap机制的理解我也有可能犯错。对于文中的有些观点,如果你有不同的理解,欢迎找我交流,一起求真。

OopMap格式

经常看到的OopMap格式,大概有这些。我列出来,大家看看有木有自己见过的,下篇文章我展开讲。

题外话

子牙手写JVM小班四期正在招生。四期新增了字节码增强+Agent,学完你就可以做JVM相关的工作,如二开arthas,自研类hsdb调试器、自研实现热更新热部署零侵入日志等黑科技…

四期完整课程包含七大专题+一个增值专题,约50多个课时。完整学完你就可以:1、用Java写一个Java虚拟机,从而深入理解运行系统的底层细节;2、有能力自行研究Hotspot源码及其他用C语言、C++写的中间件源码;3、能够用C语言、C++写任何你感兴趣的基础算法如:内存池、垃圾回收算法、主从同步算法、执行引擎、存储引擎;4、就有底子跟着我学习下半年准备开的操作系统内核班……

这套课程,横跨多个计算机学科,但只是一个学科的价格。这套课程,JVM专家、功力深厚、经验丰富的子牙老师亲授,跟我学习不踩坑,全网唯一教授虚拟机的课程…

感兴趣小伙伴可以加班班微信咨询(jvm-anan),真诚招生,无任何套路。课程试看,问题真诚解答,全部了解清楚再上车。一二三期共500多VIP加入,无一人退费,好评不断

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • OopMap
  • 聊聊GC
  • 准确式GC
  • OopMap格式
  • 题外话
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档