對於 Java 的反射使用, 通常用戶都有所瞭解。特別是在開源框架裏更是大量的使用。經過反射,咱們能拿到一個Java Class 的信息。那對於 JVM 的內部信息,像堆的使用狀況、線程、甚至是建立對象的內存地址、加載的類的內容,該怎麼辦呢?
css
其實在 JVM內,有許多內部的信息,好比上面提到的那些,就相似於生活中的內部消息同樣。你能夠想像一些大型應用,一些用戶的數據咱們只能經過 API 受權的方式拿到,普通用戶正常使用的時候,是不可能獲取到這些內容的。就像作爲運行在 JVM 上的普通 Java應用,也很難拿到 JVM 的信息,畢竟 JVM 更底層,是C++ 開發的。java
JVM 會把這些內部信息告訴我們嗎?nginx
好消息是 JVM 把這些重要的內部消息悄悄告訴了「Serviceability Agent(SA)」,對,就是咱們以前提到過的那個(Java虛擬機的顯微鏡 Serviceability Agent)。web
JVM 提供了一些對外的接口,把它的內部信息披露了出來。經過這些接口SA 才得以訪問到 JVM 內部類的結構和地址,也才能從底層觀察到 JVM內部運行的細節。tomcat
你看在SA 圖形界面的HSDB內部,長長的菜單列表,大多都是經過普通Java 應用獲取不到的「內部信息」。微信
這些都是怎麼實現的呢?說到這兒,就不得不提 gHotSpotVMStructs。app
JVM 給提供的那些接口,核心是 gHotSpotVMStructs 這個結構。它對外暴露了JVM內部的大量信息,像原始的堆的地址,線程、棧的地址等等。框架
gHotSpotVMStructs結構指向了不少類以及這些類的字段信息。每一個類都有一系列的字段,每一個字段又有本身的名字,類型,是否靜態等等。若是是靜態字段這個結構還能夠用來訪問它的值。對於一個靜態的對象字段,這個結構體還會提供目標對象的地址。經過這個根地址咱們能夠開始反查JVM內部的一些組件,包括編譯器,線程還有堆。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
相關閱讀
Java七武器系列長生劍 -- Java虛擬機的顯微鏡 Serviceability Agent
寫代碼效率不高?放過Ctrl C 和 V,讓AI來能幫你寫代碼吧
源碼|實戰|成長|職場
這裏是「Tomcat那些事兒」
請留下你的足跡
咱們一塊兒「終身成長」
![](http://static.javashuo.com/static/loading.gif)
本文分享自微信公衆號 - Tomcat那些事兒(tomcat0000)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。