When you first load a heapdump, it is unprocessed. Processing (see algorithms) involves analysing the object graph and storing data connecting the 'root's of the graph and the other objects. This includes the descendants number and total/subtree size of each object, plus classifying each object as either a non-root (N), an artificial root (A) or a pure root (R).
Processing can be performed by running the 'p' command.
Memory Usage : 41/88 mb Memory usage before process. Enter: o{a,s,t,d,m,n}, g{c,s}, t{c,s,n}, i, p, d{t,d,m} or help for more info > p Requesting at least 25 mb of heapspace to process heapdump Finding pure Roots ...................................................................... done. DFS from pure Roots ................................................................ done. DFS from objects unreached from Roots (5,385) done. Comments : Dump has flags : false # Objects : 2,045,571 # Refs : 2,635,243 # Unresolved refs : 98 Heap usage : 129,581,536 Total Object Range : 188,203,216 Pure roots : 39,082 Objects without any parents, ... which reach : 2,040,186 these reach most of the heap. Artificial roots : 373 373 'extra' roots are required to reach the remainder. Softlinks followed : 14 14 Weak,Phantom or Soft references were followed. Memory Usage : 68/88 mb Now using more memory.
Now many of the commands now have more information available. The commands in the sections below offer some further investigation techniques.
Note these options will apply to the next run of 'k' or 'p', not the current data.
Run '? p':
Follow soft,weak & phantom references ? [Y]
Enter 'N' to ignore these types of references. See soft-links
Select data to store (more data increaes memory usage) [T] total/subtree sizes(T), # descendants(D), maximum depth(M)
Select the data to be made available (here the default of only total-size (T) is selected). 'TDM' would select all 3 items of data. Note, selecting more uses more memory. See the definitions for descriptions of 'total-size', 'descendants' etc.
For example, if you selected 'DM' you would have the option (after processing again with 'p') of sorting by descendants or max-depth with 'od' or 'om' in the objects table but the total-size values would no longer be available.
The 'p' command as above starts from the pure-root with the lowest address and assigns all objects reachable to it. It then continues with the next root until all objects have been assigned/owned. This is described in Definitions & Algorithms.
If you want more information on specific object(s) then you can run:
p 0x1234 process from object 0x1234. This can be any object and clears any previous 'p {0xaddr}' data.
The effect of this is that everything reachable from 0x1234 will then have its root-owner set to 0x1234. It is quite likely that 0x1234 will now have a larger total-size than before because it owns as many objects as it can possibly reach and all these objects count towards its size.
For an example dump, I have chosen a Vector to process from (it is in-fact a root) at address 0x033b2420. Before doing this, I turned 'Descendants' on with '? p', ran 'p' and the output of 'i 0x033b2420' gave:
Total size : 51,330,568 Descendants : 95,871 Max Depth : 3
Now running:
> p 0x033b2420 Processing from 0x033b2420 'java/util/Vector' ... .....more status..... DFS from 0x033b2420 Reached 100,499 objects. Total-size is 51,591,456. Some more objects are now owned by 0x033b2420.
We can see from above that 0x033b2420 can reach 100,499 objects (this includes itself) and 'i 0x033b2420' now gives:
Total size : 51,591,456 Descendants : 100,498 This doesn't include itself Max Depth : 50
This shows that this root now owns more objects and has a deeper tree depth.
Other example queries are:
You can stop soft-links from being followed by using the settings command then repeat 'p 0x1234'. If you see differences in the reachability number then you know that not everything reached from 0x1234 is strongly reachable. You could then look at instances of reference classes e.g. start by looking at types whose name contains 'java/lang/ref'.
The command 'k 0x1234' will calculate the keep-alive size of 0x1234.
This executes by first running 'p 0x1234'. This leaves every object reachable by 0x1234 owned by it. Then any objects which are owned by 0x1234 but reachable from outside of this set are removed. This leaves 0x1234 owning exactly those objects which are only reachable thru' it.
In my Vector example above, I run:
> k 0x033b2420 Calculating keep-alive size of 0x033b2420 'java/util/Vector' ... .... status ..... Total reach (inclusive) 100,499 objects. Total-size is 51,591,456. .... status ..... Found 4,627 objects which are reachable from elsewhere. These will be taken from 0x033b2420 and then owned by other objects ... .... status ..... Keep-alive size (inclusive) is 95,872 objects. Total-size is 51,330,568.
Can now see that this Vector references about 100k objects (it is an array of objects, which themselves reference other objects) but only 5k of these objects would exist should the Vector become garbage collected. It is in a sense 'Keeping alive' 95k objects.