基于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的错误。

总结

就这么简单,你就可以实现一个统计堆里对象数以及对象大小的工具。


加入知识星球,可以有更多的交流,更多的学习和更快的提高。


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