基於SA,實現一個對象統計工具

前幾天分享了一下基於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的錯誤。

總結

就這麼簡單,你就可以實現一個統計堆裏對象數以及對象大小的工具。


加入知識星球,可以有更多的交流,更多的學習和更快的提高。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章