9

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>
Cœur
  • 37,241
  • 25
  • 195
  • 267
Trustin
  • 151
  • 1
  • 4

5 Answers5

3

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
dogbane
  • 266,786
  • 75
  • 396
  • 414
0

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.

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • thank you for comments. I think using jmap source may be good option.. it is risky on live environment.. http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Modules-sun/tools/sun/tools/jmap/JMap.java.htm – Trustin Sep 23 '10 at 12:30
0

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.

hakan
  • 1,801
  • 15
  • 14
  • I want do same thing with jmap -histo[:live] pid without changing our program. because system is live. i dont want to add overhead by adding such point cuts.also i cannot trust finilizer method for decrement the count. – Trustin Sep 21 '10 at 13:41
  • so you want to see the number of instances at a given point, i thought you wanted to see the total number of instances created. Then I think what you need is a profiling API. You can check java.lang.management package but I am not sure if it is possible to get instance counts – hakan Sep 21 '10 at 14:38
0

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);
}
dogbane
  • 266,786
  • 75
  • 396
  • 414
  • The problem is that you are waiting for the process to finish without reading the stream first. There is a limited buffer size so you need to consume it first. I added an answer covering this: https://stackoverflow.com/a/58224879/3645944 – Pablo Matias Gomez Oct 03 '19 at 18:24
0

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 (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)
...
Pablo Matias Gomez
  • 6,614
  • 7
  • 38
  • 72