找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索

[ JAVA开发技术 ] 【守望者 j2se】通过反射跟踪JVM的运行时状态

2014-10-12 11:14| 发布者: zhouy | 查看: 1219 | 收藏

摘要: 我们经常会在工作中用到反射,要么直接使用,要么通过一些框架。在Java和Scala编程里,如果想要和我们的代码进行跟踪交互,却又希望对代码透明,最主流的一个方式就是反射。不过我们用到的反射通常都局限在Java和Sca ...

我们经常会在工作中用到反射,要么直接使用,要么通过一些框架。在Java和Scala编程里,如果想要和我们的代码进行跟踪交互,却又希望对代码透明,最主流的一个方式就是反射。不过我们用到的反射通常都局限在Java和Scala代码里,并运行在JVM中。如果我们不仅是要跟踪自己的代码,还想跟踪JVM的代码怎么办呢? 


当我们开始构建Takipi站点的时候,我们想寻找一种能有效跟踪JVM堆内存的方式,以便进行一些偏底层的优化,比如扫描某个托管的内存块的地址空间。 
Java Serviceability Agent是Java一个非常强大的底层调试工具。这个工具在HotSpot JDK中自带,通过它我们不仅能查看堆里的Java对象,还能跟踪到JVM内部的C++对象,这个才是它的真正价值所在。


反射的要素: 当在运行时用反射来查看或者修改对象的时候,需要有两个基本的要素。第一个是需要查看的对象的引用(或者说地址)。第二个是这个对象结构的描述信息,包括字段的偏移量和它们的类型信息。如果支持动态方法调用,这个结构还包含了一个类方法表(vtable)的引用,以及每个方法的参数信息。 


Java的反射是相当直接的。获取一个目标对象的引用非常简单。它的字段和方法的结构也都能通过Object.getClass()方法获取到(从类的字节码中加载的)。不过问题是你怎么对JVM进行反射呢? 
开启宝库的钥匙。幸运的是,JVM通过一些对外提供的接口将它的内部类型系统暴露了出来。通过这些接口Serviceability Agent(别的工具也是类似的)才能访问JVM内部类的结构和地址。有了它们,你就可以观察从底层观察JVM内部运行的所有细节,包括原始堆的地址空间,线程/栈的地址,内部编译器的状态。 


反射的应用。你可以启动一下Serviceability Agent的Hotspot调试器来体验一下这些功能。只需要运行一下sa-jdi.jar包中的sun.jvm.hotspot.HSDB的main方法就可以了。JVM的其它一些调试工具比如 jmap,jinfo和jstack等也是基于这些基础功能来实现的。

                    
这是怎么实现的?我们来看下JVM是如何提供这些功能的。JVM库对外提供的gHotSpotVMStructs结构是这整个的基石。它暴露了JVM内部的类型系统以及根对象的地址,有了它们就可以进行对象的反射了。就像通过JNI或者JNA来动态链接到操作系统的一些值一样,你也可以这样来对它进行访问。 


问题的关键在于你如何解析这个gHotSpotVMStructs符号里面的数据。正如下表所示,JVM不仅暴露了它的内部类型系统的地址和根对象地址,还有用以解析这些数据的一些额外的符号和值。这包含类描述信息和每个字段在这个类里的偏移量。


描述信息。gHotSpotVMStructs结构指向了很多类以及它们的字段。每个类都有一系列的字段,每个字段又都包含它们的名字,类型,以及是否是静态的。如果是静态字段这个结构还可以用来访问它的值。对于一个静态的对象字段,这个结构体还会提供目标对象的地址。通过这个根地址我们可以开始反查JVM内部的一些组件,包括编译器,线程还有堆。 
你可以下载HotSpot JDK的源码来了解下Serviceability agent的具体的算法。 


开始动手吧。我们已经大概了解了这些功能到底能干什么,现在来看使用这个接口获取信息的一些具体例子。SA项目的这些人费了好多工夫来给gHotSpotVMStructs暴露出的这些类来生成Java的包装类。通过这些包装类提供出来的接口让访问JVM内部系统的工作变成非常 简单和方便,不仅保证了类型安全,同时也解决了访问和解析数据的烦恼。


为了让你能理解这个接口提供的强大的功能,下面列出了它提供的一些底层类的相关信息—— 
VM, 它是一个单实例对象,它暴露了JVM内部的许多子系统,比如线程子系统,内存管理和回收子系统。它是JVM各个子系统的入口,想要开始探索这个API的话,这是个不错的地方。


JavaThread,通过它你可以了解到JVM内部是如何处理线程的,详细到各个栈帧的位置和类型(编译的,解释执行,或者本地的),甚至本地栈和CPU寄存器的信息都有。CollectedHeap,通过它你可以看到堆的原始内容。HotSpot提供了多个垃圾回收的实现,这是那些具体实现比如 ParallelScavengeHeap的抽象基类。每个堆都是一些内存块的集合,这些内存块包含Java对象的确切地址。 
你如果看一下这些类的实现你会发现它们实际上就是使用类似反射的API来查看JVM的内存的一些硬编码的包装类。 


C++的反射。每个包装类其实就是JVM内部的C++类的一个镜像。我们都知道C++原生是不支持反射的,那么这个桥接的工作是如何完成的呢? 
这是由于JVM开发人员做了一个独特的事情。通过一系列的C++宏和许多细致的工作,HotSpot团队手动将JVM内部的C++类的字段映射并加载到了全局的gHotSpotVMStructs结构里。这才使得这些对象能从外部进行反射。真实的字段偏移量和内存布局是在JVM编译的时候生成的,这保证了导出的结构是和JVM的目标操作系统兼容的。


进程外连接。这又是一个值得一提的SA的重量级选手。SA框架中的一个很赞的功能就是它能从进程外部来查看一个活动的JVM。这是通过将SA作为一个操作系统级的调试器连接到目标的JVM来完成 的。具体的实现取决于不同的操作系统,在Linux上的话SA框架会创建一个gdb调试器的连接,在Windows上它用的则是winDbg(这个还会用到Windows Debugging Tools)。调试器框架是可扩展的,如果你想使用别的调试器的话就继承下DebuggerBase就好了。


一旦调试器连接建立起来了,返回的gHotSpotVMStruct地址就会传到调试器进程里面,它就可以查看甚至修改目标的JVM的内部对象了。这就是HSDB连接并调试目标JVM的方法,Java和JVM的代码都能进行调试。 
希望这能激起你的兴趣。我个人看来,这个架构是JVM里我喜欢的特性之一。它的优雅和开放令我惊讶不已。我们在构建Takipi的一些实时编码的模块时,它也起了很大的作用,在这里我要对它的设计者们脱帽致敬。 

本文由守望者watchmen收集整理,部分内容源于网络(http://it.deepinmind.com )。本文仅代表作者个人观点,不代表守望者的本意。如有违法侵权内容,请提交到守望者管理员处,立即处理。

推荐阅读

【守望者  j2se】ConcurrentHashMap原理分析
【守望者 j2se】ConcurrentHashMap原
集合是编程中最常用的数据结构。而谈到并发,几乎总是离不开集合这类高级数据
【守望者  j2se】双向链表模拟
【守望者 j2se】双向链表模拟
我们熟悉了java单向链表的模拟,现在我就必须开始双向链表的模拟的.1.基础结构
【守望者 高并发】现有高并发WEB服务器 lighttpd Apache Nginx比较
【守望者 高并发】现有高并发WEB服务器
lighttpd网络服务器基于的Lighttpd的网络服务器具有这样的特点:占用内存资源
【守望者 高并发】C10K/C500K与I/O框架
【守望者 高并发】C10K/C500K与I/O框架
C10K、C/500K问题C10K 的意思是10000并发请求,C500K意思是500 000并发请求,
【守望者  j2se】虚拟机各部分内存溢出情况
【守望者 j2se】虚拟机各部分内存溢出
通过简单的小例子程序,演示java虚拟机各部分内存溢出情况:(1).java堆溢出:
【守望者  JMM】理解volatile内存语义
【守望者 JMM】理解volatile内存语义
理解volatile变量对写多线程程序还是很有帮助的,这样就会避免一上来就是syn这
【守望者 高并发】使用CAS实现高效并发处理
【守望者 高并发】使用CAS实现高效并发
守望者:在并发处理应用中,一般使用锁的方式来解决竞争问题,但锁的效率比较
【守望者  j2se】吃透 java I/O 工作机制-1
【守望者 j2se】吃透 java I/O 工作机
I/O 问题可以说是当今互联网 Web 应用中所面临的主要问题之一,因为当前在这
【守望者 大数据】Mahout学习路线图
【守望者 大数据】Mahout学习路线图
Hadoop家族产品,常用的项目包括Hadoop, Hive, Pig, HBase, Sqoop, Mahout, Z
【守望者 j2se】ConcurrentMap之putIfAbsent(key,value)用法讨论
【守望者 j2se】ConcurrentMap之putIfA
先看一段代码:public class Locale { private final static MapString, Lo
【守望者  javascript】判断IE浏览器世界上最短的代码
【守望者 javascript】判断IE浏览器世
最短的IE判定var ie=!-分析以前最短的IE判定借助于IE不支持垂直制表符的特性
【守望者 大数据】机器学习已成为大数据的基石
【守望者 大数据】机器学习已成为大数
机器学习(Machine Learning, ML)是一门多领域交叉学科,涉及概率论、统计学、
【守望者  j2se】多线程与并发知识点总结
【守望者 j2se】多线程与并发知识点总
对于多线程和并发编程这个比较大的技术模块,我们会整理一些帖子方便知识点的
【守望者  j2se】二叉树模拟
【守望者 j2se】二叉树模拟
接着我们就要写一个比较复杂的数据结构的,但是这个数据结构是很重要的,假如
【守望者 SRS  】SRS 源代码分析笔记(0.9.194)-分析服务器对端口的监听 ...
【守望者 SRS 】SRS 源代码分析笔记(
第一部分 分析服务器对端口的监听 端口监听与初始化(一)全局变量_srs_confi

行业聚焦  面试交流  职位推荐  开发视频   技术交流  腾讯微博  新浪微博

友情链接:课课家教育  阿里云  鲜果  W3Cfuns前端网  中国企业家  环球企业家  投资界  传媒梦工场  MSN中文网  Android开发者社区  cnbeta  投资中国网  又拍云存储  美通说传播  IT茶馆  网商在线  商业评论网  TechOrange  IT时代周刊  3W创新传媒  开源中国社区  二维工坊  Iconfans  推酷  智能电视网  FreeBuf黑客与极客  财经网  DoNews  凤凰财经  新财富  eoe移动开发者社区  i黑马  网易科技  新浪科技  搜狐IT  创业家  创业邦  腾讯财经  福布斯中文网  天下网商  TechWeb  雷锋网  新浪创业  和讯科技  品途O2O  极客公园  艾瑞网  抽屉新热榜  卖家网  人民网通信频道  拉勾网  创新派  简单云主机  

手机版|黑名单|守望者在线 在线教育 linux 高级程序设计 C/C++ 大数据 ( 蜀ICP备14029946号

成都守望者科技有限公司 © 2013-2016 All Rights Reserved