众所周知,btrace中可以使用 com.sun.btrace.BTraceUtils.sizeof(Object)来计算传入的对象的大小;jmap -histo中也可以显示heap中对象大小信息,到底这两个显示的object size是“浅大小” 还是 “深大小”?
简单测试一下:
首先来看btrace,被测试代码如下:
public class TestBtrace{ private static final int ten_mb = 10 * 1024 * 1024; private static final int invoke_times = 100; public static void main(String[] args) throws Exception{ int index = invoke_times; while(index -- > 0){ TestBtrace test = new TestBtrace(); work(test); Thread.sleep(1000); System.out.println(index + " remains"); } } private byte[] data = new byte[ten_mb]; public static void work(Object test){ } }
btrace脚本如下:
import com.sun.btrace.BTraceUtils; import com.sun.btrace.annotations.BTrace; import com.sun.btrace.annotations.OnMethod; @BTrace public class TestBtraceScript { @OnMethod(clazz="TestBtrace", method="work") public static void interceptWork(Object object){ BTraceUtils.println(BTraceUtils.classOf(object)); BTraceUtils.println(BTraceUtils.sizeof(object)); BTraceUtils.println(); } }
原理很简单,通过拦截TestBtrace#work(Object) 计算传入的TestBtrace对象的大小。
测试脚本如下:
#!/bin/sh pid=$(jps|grep TestBtrace|cut -d ' ' -f 1) if [ -n "$pid" ] then kill -9 $pid fi javac TestBtrace.java java -Xms1000m TestBtrace > /dev/null & sleep 1; pid=$(jps|grep TestBtrace|cut -d ' ' -f 1) btrace $pid TestBtraceScript.java
执行脚本,运行结果如下:
class TestBtrace 24 class TestBtrace 24 class TestBtrace 24 class TestBtrace 24 class TestBtrace 24
OK,object大小才24 byte,而TestBtrace#data就是好几MB,所以证明com.sun.btrace.BTraceUtils.sizeof(Object)算出的是对象的浅大小。
如果有兴趣,可以修改TestBtrace 中的data的大小,再多试几次。
还是上面的TestBtrace.java ,稍微修改一下运行脚本,如下:
#!/bin/sh pid=$(jps|grep TestBtrace|cut -d ' ' -f 1) if [ -n "$pid" ] then kill -9 $pid fi javac TestBtrace.java java -Xms1000m TestBtrace > /dev/null & sleep 1; pid=$(jps|grep TestBtrace|cut -d ' ' -f 1) echo ' num #instances #bytes class name' jmap -histo $pid |grep TestBtrace
运行结果如下:
haitao-yao@haitaoyao-laptop:~/test$ sh test_jmap num #instances #bytes class name 128: 2 48 TestBtrace
由于TestBtrace 对象是不停在创建的,所以#instances 可能会有不同,但是可以肯定的是,jmap -histo 打印的也是对象的浅大小,和btrace一样。
无论是BTraceUtils.sizeof(Object) 还是 jmap -histo,显示的都是对象的浅大小,因此,在使用jmap -histo 排查内存泄漏的问题时,除了[B等基础类型外([B等基础类型已经是其真实大小),不能单纯的通过#bytes 列判断内存占用,还是要综合考虑才行。
好,祝大家玩儿的愉快!
-- EOF --