9

有没有办法以编程方式在当前的 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>
4

5 回答 5

3

您可以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
于 2010-09-21T14:14:22.107 回答
0

如果您的意思是最常用的初始化最多的类,您可以围绕构造函数定义一个切入点并跟踪每种类型的初始化。您可以为此使用 AspectJ。

于 2010-09-21T13:28:31.760 回答
0

可能需要通过JVM 工具接口 (JVM TI)或篡改 Object 的实现(这是一项棘手的工作)。

这篇文章可能很有用:使用 JVMTI 创建调试和分析代理

于 2010-09-21T12:57:11.820 回答
0

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

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);
}
于 2010-09-21T13:56:39.140 回答
0

您可以使用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 (java.base@11.0.2)
   2:          5292        7240256  [I (java.base@11.0.2)
   3:         24865         596760  java.lang.String (java.base@11.0.2)
   4:          5422         347008  java.net.URL (java.base@11.0.2)
   5:          5242         327088  [Ljava.lang.Object; (java.base@11.0.2)
...
于 2019-10-03T18:22:43.260 回答