jmap 命令的實現原理解析

當服務發生GC問題時,一般會使用jmap工具進行分析,jmap工具很強大,所以有必要了解它的方方面面。

jmap可以做什麼?

1、jmap -histo[:live]

通過histo選項,打印當前java堆中各個對象的數量、大小。

如果添加了live,只會打印活躍的對象。

jmap 命令的實現原理解析

2、jmap -dump:[live,]format=b,file=<filename> /<filename>

通過-dump選項,把java堆中的對象dump到本地文件,然後使用MAT進行分析。

如果添加了live,只會dump活躍的對象。

3、jmap -heap

通過-heap選項,打印java堆的配置情況和使用情況,還有使用的GC算法。

4、jmap -finalizerinfo

通過-finalizerinfo選項,打印那些正在等待執行finalize方法的對象。

5、jmap -permstat

通過-permstat選項,打印java堆永久代的信息,包括class loader相關的信息,和interned Strings的信息。

jmap實現原理

通過jmap和jvm之間進行通信,有兩種實現方式:attach 和 SA。

attach

attach方式,簡單來說就是客戶端和服務端之間的通信,客戶端發送請求,主要邏輯在服務端執行,jmap相當於客戶端,JVM相當於服務端。

在JVM中,有一個叫”Attach Listener”的線程,專門負責監聽attach的請求,並執行對應的操作。

比如現在執行”jmap -histo:live 5409″,一步一步的實現如下:

  1. 在Jmap.java類的main函數中,對參數進行解析。
  2. 解析出來參數中有“-histo:live”,則執行histo方法:
jmap 命令的實現原理解析

attach方法建立了jmap進程和JVM之間的socket連接,建立過程可以查看笨神的文章JVM Attach機制實現,後續基於該連接進行通信。

因為命令行中添加了[:live]選項,這裡的live參數是true。

再看看heapHisto方法

jmap 命令的實現原理解析

executeCommand方法基於之前的socket連接向JVM發送了一條”inspectheap”命令,當然了,還有參數。

虛擬機的”Attach Listener”線程當發現有新的命令時,就拿出來處理它。

命令和具體的函數對應關係如下:

jmap 命令的實現原理解析

和”inspectheap”對應的是heap_inspection方法,實現如下:

jmap 命令的實現原理解析

live_objects_only的值取決於請求中是否有”-live”,再jmap中,取決於是否有”:live”,所以不管是不是添加了”:live”,都會有STW過程,時間長短而已。

在VM_GC_HeapInspection的doit方法中

jmap 命令的實現原理解析

_full_gc的值就是live_objects_only,如果為true,可能會執行一次full gc,清空非活躍的對象,但是可能會因為GC locker,導致跳過本次的GC。

“jmap -dump”實現的原理和”jmap -histo”類似,都是通過attach的方式實現,

attach API的實現方式是:

  1. 客戶端連接到目標JVM,向其發出一個類似“inspectheap”命令;
  2. 目標JVM接收到命令,執行JVM內相關函數,將收集到的結果以文本形式返回;
  3. 客戶端接收到返回的文本並將其顯示出來;

SA

假如執行”jmap -heap 5409″,就不會使用attach方式實現了。

在參數解析中,如果參數是”-heap|-heap:format=b|-permstat|-finalizerinfo”中的一種,或者添加了”-F”,比如”jmap -histo -F 5409″,則使用SA的方式。

jmap 命令的實現原理解析

SA方式,和attach方式不同的是,相關的主要邏輯都在SA中實現,從JVM中獲取數據即可。

可以大概看下”jmap -heap”的實現,對應的實現類是”HeapSummary”,內部通過BugSpotAgent工具類attach到目標VM,更具體的底層細節,可以參考HotSpot Serviceability Agent 實現淺析

執行jmap -heap有些時候可能會導致進程變T,一般是有一個線程在等信號量,這時會block住其它所有線程,可以執行kill -CONT 進行恢復,不過還是強烈建議別執行這個命令。

jmap 命令的實現原理解析


分享到:


相關文章: