• 150403

    文章

  • 892

    评论

  • 13

    友链

  • 最近新加了换肤功能,大家多来逛逛吧~~~~
  • 喜欢这个网站的朋友可以加一下QQ群,我们一起交流技术。

JVM:有些内部信息我悄悄告诉你



对于 Java 的反射使用, 一般用户都有所了解。特别是在开源框架里更是大量的使用。通过反射,我们能拿到一个Java Class 的信息。那对于 JVM 的内部信息,像堆的使用情况、线程、甚至是创建对象的内存地址、加载的类的内容,该怎么办呢?


其实在 JVM内,有许多内部的信息,比如上面提到的那些,就类似于生活中的内部消息一样。你可以想像一些大型应用,一些用户的数据我们只能通过 API 授权的方式拿到,普通用户正常使用的时候,是不可能获取到这些内容的。就像做为运行在 JVM 上的普通 Java应用,也很难拿到 JVM 的信息,毕竟 JVM 更底层,是C++ 开发的。

JVM 会把这些内部信息告诉咱们吗?

好消息是 JVM 把这些重要的内部消息悄悄告诉了「Serviceability Agent(SA)」,对,就是我们之前提到过的那个(Java虚拟机的显微镜 Serviceability Agent)

JVM 提供了一些对外的接口,把它的内部信息披露了出来。通过这些接口SA 才得以访问到 JVM 内部类的结构和地址,也才能从底层观察到 JVM内部运行的细节。


你看在SA 图形界面的HSDB内部,长长的菜单列表,大多都是通过普通Java 应用获取不到的「内部信息」。


这些都是怎么实现的呢?说到这儿,就不得不提 gHotSpotVMStructs。

JVM 给提供的那些接口,核心是 gHotSpotVMStructs 这个结构。它对外暴露了JVM内部的大量信息,像原始的堆的地址,线程、栈的地址等等。


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


所以要获取和理解JVM 这些内部信息的关键,是在如何解析这个gHotSpotVMStructs 结构里面的数据。JVM不仅暴露了它的内部类型系统的地址和根对象地址,还有用以解析这些数据的一些额外的符号和值。这包含类描述信息和每个字段在这个类里的偏移量,此外 JVM开发者又做了一系列的工作,手动把JVM内部的C++类的字段映射并加载到了全局的gHotSpotVMStructs结构里。


SA 就是解析这些信息最好的例子。通过图形界面我们能直观感受到解析这些信息了解到了什么,通过翻译 gHotSpotVMStructs暴露出的这些信息,生成Java的包装类。通过这些包装类提供出来的接口让访问JVM内部系统的工作变的简单和方便,和普通的Java 应用使用API 类似,解决了访问和解析内部数据的烦恼。

甚至其它的一些调试工具,诊断工具也是基于这些信息来实现的。


通过我们使用SA的方式,其实是通过一个「ptrace」的系统调用,挂起目标JVM 进程,开始读取  gHotSpotVMStructs 这些内存信息。


看到上面的内容,我们大致理解了SA 的工作原理。那你如果有这样的需求,是禁止别人通过 SA 等工具来获取你JVM 的信息呢?


看,打哪儿指哪儿。答案就是重置gHotSpotVMStructs。这样工具就不能解析出来这些信息了。

Stackoverflow 上有个解决方案,是编译一个 agent,在启动JVM 的时候挂上去,并将gHotSpotVMStructs 设置为0。

extern void *gHotSpotVMStructs;
int Agent_OnLoad(void *vm, char *options, void *reserved) { gHotSpotVMStructs = 0; return 0;}


启动的时候,挂接到JVM上。

java -agentpath:/path/to/libnostructs.so ...


再去执行SA 这些工具的时候,就会抛出异常提示信息有问题

Exception in thread "main" java.lang.reflect.InvocationTargetException        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)        at java.lang.reflect.Method.invoke(Method.java:498)        at sun.tools.jstack.JStack.runJStackTool(JStack.java:140)        at sun.tools.jstack.JStack.main(JStack.java:106)Caused by: java.lang.RuntimeException: gHotSpotVMStructs was not initialized properly in the remote process; can not continue        at sun.jvm.hotspot.HotSpotTypeDataBase.readVMStructs(HotSpotTypeDataBase.java:418)        at sun.jvm.hotspot.HotSpotTypeDataBase.<init>(HotSpotTypeDataBase.java:91)        at sun.jvm.hotspot.HotSpotAgent.setupVM(HotSpotAgent.java:395)        at sun.jvm.hotspot.HotSpotAgent.go(HotSpotAgent.java:305)        at sun.jvm.hotspot.HotSpotAgent.attach(HotSpotAgent.java:140)        at sun.jvm.hotspot.tools.Tool.start(Tool.java:185)        at sun.jvm.hotspot.tools.Tool.execute(Tool.java:118)        at sun.jvm.hotspot.tools.JStack.main(JStack.java:92)        ... 6 more


相关阅读

Sentinel 是怎样拦截异常流量的?

快放开那些捣乱的猴子!

Java七武器系列孔雀翎-- 问题诊断神器BTrace

Java七武器系列长生剑 -- Java虚拟机的显微镜 Serviceability Agent

写代码效率不高?放过Ctrl C 和 V,让AI来能帮你写代码吧

不用Jar 包的Agent?几行代码实现运行时增强?

怎样阅读源代码?




源码|实战|成长|职场


这里是「Tomcat那些事儿

请留下你的足迹

我们一起「终身成长」

本文分享自微信公众号 - Tomcat那些事儿(tomcat0000)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。


695856371Web网页设计师②群 | 喜欢本站的朋友可以收藏本站,或者加入我们大家一起来交流技术!

0条评论

Loading...


发表评论

电子邮件地址不会被公开。 必填项已用*标注

自定义皮肤 主体内容背景
打开支付宝扫码付款购买视频教程
遇到问题联系客服QQ:419400980
注册梁钟霖个人博客