Summarizing Java heap utilization with jmap


Java has become one of the most successful languages to hit the IT industry. One of the reasons behind it’s high rate of adoption is that fact that Java manages memory resources for the programmer. This makes programming significantly easier, but introduces additional complexity, since engineers need to size the Java heap and pick a garbage collection algorithm (or in the case of generational collectors, more than one) that best matches an application’s workload. Fortunately, two extremely useful tools allow you to observe the Java heap: the DTrace hotspot provider and the Java jmap utility. In this blog post, I will discuss the jmap utility.

The Java jmap utility provides a number of useful options to summarize heap usage, and get a break down of objects in the new and old generations. To summarize the new and old generations, the jmap utility can be run with the “-heap” option, and the PID of the JVM to summarize (the PID can be acquired by running the jps utility, or by reviewing the ps output):

$ jmap -heappgrep java``

Attaching to process ID 5365, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 1.6.0_01-b06

using parallel threads in the new generation.
using thread-local object allocation.
Concurrent Mark-Sweep GC

Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 1073741824 (1024.0MB)
NewSize = 268435456 (256.0MB)
MaxNewSize = 268435456 (256.0MB)
OldSize = 805306368 (768.0MB)
NewRatio = 7
SurvivorRatio = 6
PermSize = 21757952 (20.75MB)
MaxPermSize = 88080384 (84.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 234881024 (224.0MB)
used = 102062424 (97.33431243896484MB)
free = 132818600 (126.66568756103516MB)
43.452818053109304% used
Eden Space:
capacity = 201326592 (192.0MB)
used = 94318424 (89.94905853271484MB)
free = 107008168 (102.05094146728516MB)
46.84846798578898% used
From Space:
capacity = 33554432 (32.0MB)
used = 7744000 (7.38525390625MB)
free = 25810432 (24.61474609375MB)
23.07891845703125% used
To Space:
capacity = 33554432 (32.0MB)
used = 0 (0.0MB)
free = 33554432 (32.0MB)
0.0% used
concurrent mark-sweep generation:
capacity = 805306368 (768.0MB)
used = 15032688 (14.336288452148438MB)
free = 790273680 (753.6637115478516MB)
1.8667042255401611% used
Perm Generation:
capacity = 50577408 (48.234375MB)
used = 30285240 (28.88225555419922MB)
free = 20292168 (19.35211944580078MB)
59.87898786746842% used

The jmap output contains the size of eden (the place where new objects are created), each survivor space, the old generation and the permanent generation. If you aren’t familiar with the generations that are used in modern JVMs, you might want to take a look at Tony Printezis’ article on this topic.

In addition to printing summary data, jmap can also be used to display the objects in the heap.

$ jmap -histopgrep java|more

num #instances #bytes class name
--------------------------------------
1: 224437 27673848 [C
2: 38611 23115312 [B
3: 47801 12187536 [I
4: 208624 8344960 java.lang.String
5: 45332 6192904 <constMethodKlass>
6: 45332 5450864 <methodKlass>
7: 3889 4615536 <constantPoolKlass>
8: 45671 4193136 [Ljava.lang.Object;
9: 66203 3222312 <symbolKlass>
10: 3889 3192264 <instanceKlassKlass>
11: 3455 2999296 <constantPoolCacheKlass>
12: 19754 1106224 java.nio.HeapCharBuffer

< ..... >

This summary contains the type of each object (e.g., “[C” would refer to arrays of characters), the number of objects of each type as well as the total number of bytes these objects take up in the heap. Jmap additionally allows you to filter the output to display only the live objects:

$ jmap -histo:live 698

num #instances #bytes class name
--------------------------------------
1: 45256 6185464
2: 45256 5441744
3: 6899 5201176 [B
4: 3851 4577776
5: 29133 4259592 [C
6: 66069 3213448
7: 3851 3169464
8: 3417 2970112
9: 29714 1188560 java.lang.String
10: 1553 745224
11: 4161 732336 java.lang.Class

< ..... >

There are also jmap options to dump the heap to a file, display the contents of the permanent generation and view obejcts that are awaiting finalization. Jmap is an incredibly useful tool, and in my next blog post I will show how the DTrace hotspot provider can be used to dig into object allocation in much more detail.

This article was posted by Matty on 2007-10-27 16:32:00 -0400 EDT