镜像镜像–使用反射在运行时查看JVM内部
开发人员:Takipi会告诉您何时新代码在生产中中断– 了解更多
我们都习惯于在我们的日常工作中直接或通过利用反射的框架来运用反射。 它是Java和Scala编程的主要方面,它使我们使用的库可以与我们的代码进行交互,而无需对其进行硬编码的知识。 但是我们对反射的使用仅限于在JVM中运行的Java和Scala代码。 如果我们可以使用反射不仅在运行时查看我们的代码,而且还查看JVM的代码怎么办?
当我们开始构建Takipi时 ,我们寻求一种有效地分析JVM堆内存以启用一些低级优化的方法,例如扫描托管堆块的地址空间。 我们遇到了许多有趣的工具和功能来检查JVM状态的各个方面,其中之一就是这样做的。
它是Java最强大,最底层的调试工具之一-Java Serviceability Agent 。 HotSpot JDK附带了这个功能强大的工具,使我们不仅可以查看堆中的Java对象,还可以查看构成JVM本身的内部C ++对象,这才是真正的魔力。
反射成分 。 当处理任何形式的反射以在运行时动态检查和修改对象时,需要两个基本要素。 第一个是要检查的对象的引用(或地址)。 第二个是对对象结构的描述,其中包括对象字段所在的偏移量及其类型信息。 如果支持动态方法调用,则该结构还将包含对类的方法表(例如vtable)的引用以及每个人期望的参数。
Java反射本身非常简单。 您将获得对目标对象的引用,就像对其他对象一样。 通过通用Object.getClass方法(最初从类的字节码加载)可以使用其字段和方法结构。 真正的问题是您如何反映JVM本身?
城堡的钥匙 。 足够令人惊奇的是,JVM通过一组公开导出的符号公开了其内部类型系统。 这些符号为Serviceability代理(或与此有关的任何其他代理)提供对内部JVM类系统的结构和地址的访问权限。 通过这些,可以在最低级别检查JVM内部工作的几乎所有方面,包括诸如原始堆地址,线程/堆栈地址和内部编译器状态之类的内容。
在行动中反思 。 为了了解各种可能性,您可以通过启动Serviceability Agent的HotSpot Debugger UI来查看其中的一些功能。 您可以通过使用sun.jvm.hotspot.HSDB作为主类参数启动sa-jdi.jar来完成此操作。 您将看到的功能与帮助JVM某些最强大的调试工具(例如jmap,jinfo和jstack)的功能相同。
HSDB以及它提供给目标JVM的某些极低级别的检查功能。
怎么做的 。 让我们仔细研究一下JVM如何实际提供这些功能。 这种方法的基础是由jvm库公开导出的gHotSpotVMStructs结构。 该结构公开了内部JVM类型系统以及我们可以从中开始反映的根对象的地址。 可以像通过JNI或JNA与任何公开导出的OS库符号动态链接一样访问该符号。
然后问题就变成了如何解析gHotSpotVMStructs符号公开的地址中的数据? 如下表所示,JVM不仅公开其类型系统的地址和根地址,还公开了其他符号和值,这些符号和值为您提供了解析数据所需的值。 这些包括类描述符和类类中每个字段所在的二进制偏移量。
* jvm.dll公开的符号的依赖项遍历屏幕截图
清单 。 gHotSpotVMStructs结构指向类及其字段的列表。 每个类都提供一个字段列表。 对于每个字段,结构都提供其名称,类型以及其静态字段还是非静态字段。 如果它是静态字段,则该结构还将提供对其值的访问。 在静态对象类型字段的情况下,该结构将提供目标对象的地址。 此地址是一个根,我们可以从中开始反映内部JVM系统的特定组件。 这包括诸如编译器,线程或收集的堆系统之类的东西。
您可以在此处签出Serviceability代理用来解析Hotspot JDK代码中的结构的实际算法。
实际例子 。 现在,我们对这些功能可以做什么有了一个广泛的了解,让我们看一下此接口公开的数据类型的一些具体示例。 构建SA代理的人员在围绕gHotSpotVMStructs表提供的大多数类创建Java包装程序时遇到了很多麻烦。 这些提供了一种非常干净和简单的API,以既安全类型又隐藏访问和解析数据所需的大多数二进制工作的方式访问内部系统的大部分。
为了让您大致了解此API提供的一些强大功能,以下是对它提供的低级类的一些引用-
VM是单例类,它公开了许多JVM的内部系统,例如线程系统,内存管理和收集功能。 它是许多JVM子系统的切入点,并且是探索此API的良好起点。
JavaThread使您从内部了解JVM如何从内部看到Java线程,并深入了解框架位置和类型(编译,解释,本机…)以及实际本机堆栈和CPU寄存器信息。
CollectedHeap使您可以浏览收集到的堆的原始内容。 由于HotSpot包含多个GC实现,因此这是一个抽象类,具体的实现(例如ParallelScavengeHeap)从该抽象类继承。 每个提供一组内存区域,其中包含Java对象所在的实际地址。
当您查看每个类的实现时,您会发现它实际上只是一个硬编码包装器,使用类似于反射的API来查看JVM的内存。
C ++中的反射 。 这些Java包装器中的每一个都被设计为JVM中内部C ++类的几乎完整的镜像。 众所周知,C ++没有本机反射功能,这引发了如何创建该桥的问题。
答案在于JVM开发人员所做的非常独特的事情。 通过一系列C ++宏和大量艰苦的工作,HotSpot团队手动将数十个内部C ++类的字段结构映射并加载到全局gHotSpotVMStructs中。 这个过程使它们可用于从外部反射。 实际的字段偏移量值和布局是在JVM编译时生成的,有助于确保导出的结构与JVM的目标OS兼容。
进程外连接 。 Serviceability代理还有一个更强大的方面值得一看。 SA框架提供的最酷的功能之一是能够从进程外反映外部实时JVM。 这是通过将Serviceability代理作为操作系统级别的调试器附加到目标JVM来完成的。 由于这取决于操作系统,因此对于Linux,SA代理框架将利用gdb调试器连接。 对于Windows,它将使用winDbg(这意味着将需要Windows调试工具)。 调试器框架是可扩展的,这意味着可以通过扩展抽象的DebuggerBase类来使用另一调试器 。
建立调试器连接后,gHotSpotVMStruct的返回地址值将传递回调试器进程,该进程可以(借助OS)开始检查甚至修改目标JVM的内部对象系统。 HSDB正是通过这种方式,您可以连接和调试目标JVM(包括Java和JVM代码)。
* HSDB的界面公开了SA代理反映目标JVM进程的能力
我希望这引起了您的兴趣。 从我个人的角度来看,该体系结构是我最喜欢的JVM之一。 在我看来,它的优雅和开放绝对令人赞叹。 当我们构建Takipi的一些实时编码部分时,这对我们也非常有帮助,因此对于设计它的优秀人员来说,这是一个很大的窍门。
翻译自: https://www.javacodegeeks.com/2014/01/mirror-mirror-using-reflection-to-look-inside-the-jvm-at-run-time.html
镜像镜像–使用反射在运行时查看JVM内部相关推荐
- jvm优化_镜像镜像–使用反射在运行时查看JVM内部
jvm优化 开发人员:Takipi会告诉您何时新代码在生产中中断–了解更多 我们都习惯于在我们的日常工作中直接或通过利用反射的框架来运用反射. 它是Java和Scala编程的主要方面,它使我们使用的库 ...
- jvm 内存镜像_镜像镜像–使用反射在运行时查看JVM内部
jvm 内存镜像 开发人员:Takipi会告诉您何时新代码在生产中中断– 了解更多 我们都习惯于在我们的日常工作中直接或通过利用反射的框架来运用反射. 它是Java和Scala编程的主要方面,它使我们 ...
- python怎么在运行中查看执行状态_python,_python程序运行时 查看对象状态,python - phpStudy...
python程序运行时 查看对象状态 不知大家有没有用过Rthymbox的python console. Rthymbox可以在运行的时候,让它的 交互式命令行 对程序进行控制. 比如说可以调用pla ...
- Java反射运行时_java反射获得运行时属性的值
运行时动态获得属性的值(通过方法获得): Method[] methods = cls.getDeclaredMethods(); for (Method method : methods) { if ...
- Python3运行时查看线程信息
前一篇文章说了一下在是用Python2的情况下怎样查看运行时线程信息,今天查资料的时候发现,原来在Python3中引入了 faulthandler 模块,可以简化我们很多工作,甚至,如果不需要保持进程 ...
- 使用Emit反射建立运行时实体模型
做这个功能目的是对旧项目代码分析管理,代码规划. 如果重头开发,统一一个框架小框架搞,人.时间到位都不是问题.但是旧应用系统优化,项目更新,就几个人开发加维护,接口层越多,bll层越来越厚,人来人往留 ...
- 通过反射--操作运行时类中的指定的属性/方法
操作运行时类中的指定的属性: 1.getDeclaredField(String fieldName):获取运行类中指定变量名的属性: 2.保证当前属性时可访问的 : 属性.setAccessible ...
- python怎么在运行中查看执行状态,Python程序运行时查看对象状态怎样设计才能实现...
不知大家有没有用过Rthymbox的python console. Rthymbox可以在运行的时候,让它的 交互式命令行 对程序进行控制. 比如说可以调用player的play函数,让它播放, 还可 ...
- 1.Containerd容器运行时初识与尝试
0x00 前言简述 1.基础介绍 2.专业术语 3.架构简述 0x01 安装配置 1.Ubuntu安装Containerd.io流程 0x02 简单使用 1.镜像拉取与运行 2.创建和使用网络 3.与 ...
最新文章
- C语言网络编程:多路IO select实现多客户端
- 6月27日比特币现金消息总结
- Azure运维系列 3:善用Azure捕获功能事半功倍
- Windows Server 2012 R2配置ISCSI磁盘共享盘(4)
- 数据分析:2020年3月汽车工业经济运行情况
- python保存的是什么类型文件_python-----基本的数据类型和文件操作
- std::priority_queue
- kotlin 字符串_Kotlin程序确定字符串是否具有所有唯一字符
- sublimeText3安装emmet(For Mac)
- echarts 叠加柱状图柱顶显示百分比
- python Crypto.Cipher
- 最新的软著自助免费申请教程!
- 【矩阵论】单射、满射与双射
- php session fixation,Session Fixation 原理与防御
- BUUCTF刷题笔记
- 深度学习和自然语言处理的应用
- 安装PHPStudy(小皮)V8.1最详细安装教程
- Java时间处理(UTC时间和本地时间转换)
- springboot大学生就业管理系统毕业设计源码290915
- 《地理信息系统导论》 坐标系统 复习题
热门文章
- 以计算机网络为中介的人际传播,以计算机为中介的人际传播理论范式
- java后台 flex前台例子_flex+blazeds+java后台消息推送(简单示例)
- python开发工具下所有软件都打不开_Python 开发工具链全解
- 使用Eclipse构建Maven项目 (step-by-step)
- jdk内置线程实例_EA问题的JDK14实例
- 设计模式 工厂方法_工厂方法设计模式
- java uuid_Java UUID
- 动态调整线程池_调整线程池的重要性
- adf4351使用_使用ADF BC管理保存点
- Java 14:查看更新的switch语句