前幾天分享了一下基於Attach API實現一個jstack功能的demo, 於是有圈友私下問我,什麼是SA?如果基於SA如何實現jstack?
本篇片呢就介紹下SA,以及使用SA來開發一個統計JVM堆裏對象的工具。
簡介
SA全稱Serviceability Agent,它是hotspot虛擬機開發人員,爲了調試虛擬機而開發的一個組件。它是利用操作系統底層API來讀取一個進程的數據。
它與Attach API最大的不同是:attach通過連接到目標JVM進程,讓目標JVM進程執行相關命令來實現;而sa是獨立於目標JVM進程運行。
之前我們介紹的HSDB就是基於SA來實現的。SA只能支持讀取一個進程的快照信息,換句話說,當採用SA連接到目標進程時,目標進程會暫停住,直到斷開連接後目標進程纔會繼續運行。所以切勿在線上環境使用基於SA的工具。
對象統計工具
有了以上對SA的瞭解,接下來就看看如何基於SA開發一個統計對象的工具。
jdk通過sa-jdi.jar提供了相關的工具類,我們可以基於這些類很簡單的實現這個功能。直接上代碼:
public class TestSA extends Tool {
@Override
public void run() {
Map<Klass,Value> map = new HashMap<>();
ObjectHeap objectHeap = VM.getVM().getObjectHeap();
objectHeap.iterate(new HeapVisitor() {//遍歷堆裏的對象
@Override
public void prologue(long l) {
}
@Override
public boolean doObj(Oop oop) {
Klass klass = oop.getKlass();//獲取對象的class
Value value = map.get(klass);
if(value == null){
value = new Value();
map.put(klass,value);
}
value.increase();//對象數目加一
value.add(oop.getObjectSize());//對象大小
return false;
}
@Override
public void epilogue() {
}
});
for(Map.Entry<Klass,Value> entry:map.entrySet()){
StringBuilder sb = new StringBuilder("name:");
sb.append(entry.getKey().getName().asString())
.append("---count:").append(entry.getValue().getCount())
.append("---size:").append(entry.getValue().getSize());
System.out.println(sb.toString());
}
}
private class Value{
private int count = 0;
private long size = 0;
public void increase(){
count++;
}
public void add(long size){
this.size+=size;
}
public int getCount(){
return count;
}
public long getSize(){
return size;
}
}
public static void main(String[] args) {
TestSA testSA = new TestSA();
testSA.execute(args);
}
}
我們只需要繼承Tool類(一定是sun.jvm.hotspot.tools.Tool哦),然後重寫run方法,在run方法裏調用相關api來獲取數據。
運行這個類時,記得要用管理員權限哦,還要指定要統計的jvm進程的pid。如下是我運行這個類的命令:
sudo java -cp .:$JAVA_HOME/lib/sa-jdi.jar sa.TestSA 1288
還需要強調的是,這個命令要在sa.TestSA類所在的目錄下運行,否則會報找不到TestSA的錯誤。
總結
就這麼簡單,你就可以實現一個統計堆裏對象數以及對象大小的工具。
加入知識星球,可以有更多的交流,更多的學習和更快的提高。