以编程方式打印类直方图

发布于 2024-09-24 11:22:30 字数 542 浏览 6 评论 0原文

有没有办法以编程方式打印当前java应用程序中最常用的N个类?

样本输出:N=10

num   #instances    #bytes  class name
--------------------------------------
  1:        23     4723136  [I
  2:        19     4718928  [J
  3:        18     4718880  [D
  4:     73925     1774200  java.lang.String
  5:       208     1226400  [C
  6:        28     1205064  [B
  7:        18     1179936  [F
  8:        68      297040  [Ljava.lang.String;
  9:       332       14136  [Ljava.lang.Object;
 10:        32       10240  <objArrayKlassKlass>

is there any way to print top used N classes on the current java application programmatically?

sample output: N=10

num   #instances    #bytes  class name
--------------------------------------
  1:        23     4723136  [I
  2:        19     4718928  [J
  3:        18     4718880  [D
  4:     73925     1774200  java.lang.String
  5:       208     1226400  [C
  6:        28     1205064  [B
  7:        18     1179936  [F
  8:        68      297040  [Ljava.lang.String;
  9:       332       14136  [Ljava.lang.Object;
 10:        32       10240  <objArrayKlassKlass>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

蘸点软妹酱 2024-10-01 11:22:56

您可以使用 Runtime#exec 以编程方式运行 jmap,如下所示:

String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
Process p = Runtime.getRuntime().exec("jmap -histo " + pid);

BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
    System.out.println(line);
}
br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = br.readLine()) != null) {
    System.out.println("ERR:" + line);
}
p.waitFor();

输出将是:

 num     #instances         #bytes  class name (module)
-------------------------------------------------------
   1:         55905       40469648  [B ([email protected])
   2:          5292        7240256  [I ([email protected])
   3:         24865         596760  java.lang.String ([email protected])
   4:          5422         347008  java.net.URL ([email protected])
   5:          5242         327088  [Ljava.lang.Object; ([email protected])
...

You can use Runtime#exec programatically to run a jmap like this:

String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
Process p = Runtime.getRuntime().exec("jmap -histo " + pid);

BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
    System.out.println(line);
}
br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = br.readLine()) != null) {
    System.out.println("ERR:" + line);
}
p.waitFor();

And the output will be:

 num     #instances         #bytes  class name (module)
-------------------------------------------------------
   1:         55905       40469648  [B ([email protected])
   2:          5292        7240256  [I ([email protected])
   3:         24865         596760  java.lang.String ([email protected])
   4:          5422         347008  java.net.URL ([email protected])
   5:          5242         327088  [Ljava.lang.Object; ([email protected])
...
冷清清 2024-10-01 11:22:51

我认为你不能在同一个 JVM 中完成它,因为你需要遍历对象堆,并且最终可能会陷入无限循环。出于好奇,我尝试在同一个 JVM 甚至不同的 JVM 上使用 Runtime.exec 生成 jmap,但它只是挂起?

String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
//pid=2520
System.out.println("PID: " + pid);
Process p = Runtime.getRuntime().exec("jmap -histo " + pid);
p.waitFor();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line ;
while((line = br.readLine())!=null){
    System.out.println(line);
}

br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while((line = br.readLine())!=null){
    System.out.println(line);
}

I don't think you can do it within the same JVM because you need to traverse the object heap, and you might end up going in an infinite loop. Just out of curiosity, I tried spawning jmap using Runtime.exec against the same JVM and even against a different JVM and it just hangs?

String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
//pid=2520
System.out.println("PID: " + pid);
Process p = Runtime.getRuntime().exec("jmap -histo " + pid);
p.waitFor();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line ;
while((line = br.readLine())!=null){
    System.out.println(line);
}

br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while((line = br.readLine())!=null){
    System.out.println(line);
}
酒浓于脸红 2024-10-01 11:22:48

如果您的意思是最常用的初始化最多的类,您可以在构造函数周围定义切入点并跟踪每种类型的初始化。您可以使用 AspectJ 来解决这个问题。

If you mean by top used, classes that are initialized most, you can define a pointcut around the constructors and keep track of the initializations for each type. You can use AspectJ for that matter.

清引 2024-10-01 11:22:44

可能需要经过 JVM 工具接口 (JVM TI) 或篡改 Object 的实现(这是一件棘手的事情)。

这篇文章也许有用:使用 JVMTI 创建调试和分析代理。

Probably not without going through JVM Tool Interface (JVM TI) or tampering with the implementation of Object (which is a tricky business).

This article is perhaps useful: Creating a Debugging and Profiling Agent with JVMTI.

恰似旧人归 2024-10-01 11:22:41

您可以启动 jmap 作为 java 包装器脚本的一部分,并在循环中连续运行它:

例如,如果您在 Unix 上,您可以执行以下操作:

java MyMainClass ... &

pid=$!
while [ ! -z $pid ]
do
    jmap -histo $pid | head -13
    sleep 60

    #check pid
    kill -0 $pid > /dev/null 2>&1   
    if [ $? -ne 0 ]
    then
       pid=""
    fi  
done

You could kick off jmap as part of your java wrapper script and run it continuously in a loop:

For example, if you are on Unix, you could do something like:

java MyMainClass ... &

pid=$!
while [ ! -z $pid ]
do
    jmap -histo $pid | head -13
    sleep 60

    #check pid
    kill -0 $pid > /dev/null 2>&1   
    if [ $? -ne 0 ]
    then
       pid=""
    fi  
done
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文