jvm 内存镜像_镜像镜像–使用反射在运行时查看JVM内部
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内部的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 支行备案条件银监局(支行备案)
- 下一篇: 谁去过顽皮,谁去过尼斯? 圣诞老人为您提