2014年3月5日星期三

HeapAudit 使用

使用方法## #HeapAudit# HeapAudit是foursquare开发的一个profile java内存消耗的小工具, 用来追踪 Java程序在Heap上的内存分配
github: heapaudit
官方介绍: HeapAudit - JVM Memory Profiler for the Real World

使用方法##

跟btrace等一个路数, 实现了attach功能和随java程序启动的agent功能.

attach

对于已经启动的Java程序, 拿到pid后执行
java -Xbootclasspath/a:/usr/lib/jvm/java-openjdk/lib/tools.jar -jar heapaudit-1.1.5.jar $java_pid -Itest.HeapTest@test.+
Press <enter> to exit HeapAudit...
HEAP: test/HeapTest@test()V x1
      - char[3] (24 bytes) x144
      - java.lang.Integer[133] (551 bytes) x21
      - java.lang.Integer[91] (380 bytes) x64
      - java.lang.Integer[43] (188 bytes) x32
      - java.lang.Integer[19] (92 bytes) x16
      - java.lang.Integer[7] (44 bytes) x8
      - java.lang.Integer[1] (22 bytes) x3
      - java.lang.StringBuilder (24 bytes) x144
      - java.util.HashMap (56 bytes) x1
      - java.util.HashMap$Entry[256] (1040 bytes) x2
      - java.util.HashMap$Entry[128] (528 bytes) x2
      - java.util.HashMap$Entry[64] (272 bytes) x2
      - java.util.HashMap$Entry[32] (144 bytes) x2
      - java.util.HashMap$Entry[16] (80 bytes) x1
      - java.util.HashMap$Entry (32 bytes) x288
  • 由于使用到了attach api, 需要找到tools.jar位置. 一般是$JAVA_HOME/lib/tools.jar
  • -Itest.HeapTest@test.+ 代表匹配class name为test.HeapTest 方法名为testXXX的方法
  • 还有一个有用的选项是-Xtimetou=X 代表几秒后自动断开, 非常实用
  • HeapAudit 在退出时会自动恢复修改过的bytecode. 性能损耗很小

随Java程序启动

启动是带上-javaagent 参数
java -javaagent:heapaudit.jar XXX
这种实现的目的是在要profile的代码中已经显试加上了profile的代码, 如下:
HeapQuantile r = new HeapQuantile();
// 这里仅仅统计当前线程, 使用HeapRecorder.Threading.Local
HeapRecorder.register(r, HeapRecorder.Threading.Local);
MyObject o = new MyObject();
HeapRecorder.unregister(r, HeapRecorder.Threading.Local);
for (HeapQuantile.Stats s: r.tally(HeapRecorder.Threading.Local, true)){        
    System.out.println(s);
}
这种是侵入性非常大的方式. 必须在代码中引入heapaudit 依赖并添加代码. 灵活性非常低.

比较两种方式优劣

factor attach javaagent启动
侵入性 高, 需要修改业务代码, 启动脚本
性能损耗 same same
全局统计 支持 支持, coding 指定, 无法修改
按照线程统计 不支持 支持, coding 指定, 无法修改

Alternative

大多数情况下, 我们想知道单次用户请求某个方法分配的内存情况. 并且随着trouble shooting的深入, 需要profile的类肯定会变化. 因此我们需要attach + 单线程统计功能
第一个想到的是给HeapAudit提pull request. 不过没有来得及. 第二个就是请出btrace. 关闭unsafe功能后, 直接插入代码. 需要在应用启动时加入heapaudito 的 javaagent 关于关闭btrace的unsafe功能, 参见这里. 建议使用老版本btrace. 刚才尝试新版本btrace无法关闭unsafe.
  1. 启动目标java 程序:
    java -javaagent:heapaudit-1.1.5.jar -cp test.jar test.HeapTest
  2. attach 上去:
    btrace -cp heapaudit-1.1.5.jar $(jps |grep HeapTest|awk '{print $1}') HeapTest_Script.java
脚本:
// HeapTest_Script.java
import static com.sun.btrace.BTraceUtils.*;

import com.sun.btrace.annotations.*;
import com.foursquare.heapaudit.*;
import com.foursquare.heapaudit.HeapRecorder;

@BTrace
public class HeapTest_Script {


        @TLS
        private static HeapQuantile recorder;

        @OnMethod(clazz = "test.HeapTest", method = "test")
        public static void onCall_test() {

                recorder = new HeapQuantile();
                HeapRecorder.register(recorder, HeapRecorder.Threading.Local);
        }

        @OnMethod(clazz = "test.HeapTest", method = "test", location = @Location(Kind.RETURN))
        public static void onReturn_test() {
                println(currentThread().getName() + " get test");
                HeapRecorder.unregister(recorder, HeapRecorder.Threading.Local);
                for (HeapQuantile.Stats s: recorder.tally(HeapRecorder.Threading.Local, true)){
                    println(s);
                }
        }
}

总结

好了. 可以quick && dirty的满足需求了.
--EOF--

1 条评论:

  1. 大家好,我的名字是福莫萨迪库住在马林迪市肯尼亚我想告诉多一点关于一个好心人叫本杰明·布里尔·李与资助服务作为贷款官员,本杰明·布里尔·李先生帮我得到了37,115,225.00先令的贷款,我试图回到我的脚提高 我的生意,我知道有一些在财政困难,与本杰明先生谈什么应用程序+1-989-394-3740或他的个人电子邮件Lfdsloans@outlook.com我很高兴他为我做了什么,他的银行会计师以及会计师埃尔南德斯卢卡斯非常感谢你的工作做得很好。

    回复删除