占小狼妹蔽,轉(zhuǎn)載請注明原創(chuàng)出處欧芽,謝謝症脂!
jmap倡缠、jstack等工具可以訪問虛擬機中的堆對象、線程信息等迫皱,可以通過兩種方式實現(xiàn)
1歉闰、attach方式
2辖众、SA方式
attach方式
這種方式,在之前的文章已經(jīng)分析過和敬,底層通過socket進行通信凹炸,jmap進程好比一個客戶端,運行的虛擬機看成服務端昼弟,有一個叫"Attach Listener"的線程啤它,專門負責監(jiān)聽attach的請求,并在虛擬機中執(zhí)行對應的代碼舱痘。
更多詳情點擊 jmap命令的實現(xiàn)原理解析
SA方式
首先变骡,我們先看看SA可以做什么?
1芭逝、從運行的Java進程中讀取數(shù)據(jù)
2塌碌、從數(shù)據(jù)中,解析出所有Hotspot數(shù)據(jù)結(jié)構(gòu)
3旬盯、從Hotspot數(shù)據(jù)結(jié)構(gòu)中國台妆,解析出所有的Java對象
這里需要清楚的是:
SA是運行在單獨的進程中,和目標Java進程是隔離的胖翰,而且在使用SA工具時接剩,不會在目標Java進程中執(zhí)行任何代碼,而是讀取目標Java進程中的數(shù)據(jù)萨咳,然后在自身進程中處理懊缺,在SA讀取數(shù)據(jù)時,目標Java進程會被掛起培他。
那么鹃两,SA是如何讀取到目標Java進程的呢?不同的系統(tǒng)靶壮,有不同的方式:
1怔毛、Solaris系統(tǒng)中员萍,通過 libproc 實現(xiàn)
2腾降、Linux系統(tǒng)中,通過 /proc和ptrace 實現(xiàn)
3碎绎、Windows系統(tǒng)中螃壤,通過 dbgeng.dll library 實現(xiàn)
下面以Linux為例强衡,看看是如何一步一步實現(xiàn)的嫉到。
假設執(zhí)行"jmap -heap <pid>",該命令對應的實現(xiàn)類
"sun.jvm.hotspot.tools.HeapSummary.java"
SA的工具類都繼承了Tool類监署,通過start方法啟動日麸,start方法中會初始化一個BugSpotAgent寄啼,并通過BugSpotAgent的attach方法與目標Java進程建立聯(lián)系逮光,attach方法實現(xiàn)如下:
在setupDebugger方法中,根據(jù)不同平臺初始化debugger墩划,attach動作最終由具體的平臺相關的JVMDebugger對象完成涕刚,在Linux平臺,使用LinuxDebuggerLocal對象乙帮,LinuxDebuggerLocal類中具體的attach實現(xiàn)如下:
最終調(diào)用了一個本地方法
private native void attach0(int pid) throws DebuggerException;
本地方法attach0的實現(xiàn)位于LinuxDebuggerLocal.c
中
在本地方法attach0中杜漠,看到有一個Pgrab方法,跟進去...
Pgrab方法的注釋也說明該方法可以attach到目標進程上察净,從ptrace_attach方法再跟進去...
這里驾茴,我們看到了ptrace命令
ptrace(PTRACE_ATTACH, pid, NULL, NULL)
其中PTRACE_ATTACH,可以實現(xiàn)attach到一個指定pid的進程氢卡。
SA成功attach到目標Java進程之后锈至,執(zhí)行setupVM,初始化Hotspot數(shù)據(jù)結(jié)構(gòu)异吻,之后的數(shù)據(jù)獲取通過/proc實現(xiàn)裹赴,這里不再深入分析了。