继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

基于SA,实现一个对象统计工具

青春有我
关注TA
已关注
手记 1206
粉丝 205
获赞 1008

前几天分享了一下基于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的错误。



作者:_清泉_
链接:https://www.jianshu.com/p/a906dbf3cbed


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP