前几天分享了一下基于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
随时随地看视频