Profiling Results - Memory Usage
When you analyse memory usage, the Profiling Results tab displays data on object allocation and liveness.
These results are displayed when you choose the following profiling tasks:
When you analyze memory usage, the profiling results displayed depend on which of the
following options you choose:
- Record both object creation and garbage collection (Object Liveness)
This option provides information about how many objects
of each type are still alive, as well as data on live objects.
- Record object creation (Object Allocation)
This option gives you information about the
number, type, and location of objects that have been allocated.
This profiling mode is a functional subset of object liveness profiling.
The reason for having both modes is that pure object allocation profiling
has a smaller performance and memory overhead.
To open the Profiling Results tab, click the Live Results button
(
) in the Profiler window.
Object Liveness Results
When you profile object liveness, the following information is displayed
in the Profiling Results tab. (Click here for
an example of the Profiling Results for Object Liveness.)
- Live bytes (graph)
- Live bytes (number)
- Live Objects
This is the size and number of tracked live objects for the given class
at this moment. Tracked objects are a subset of all the allocated objects
for which stack traces are collected, size is determined, and the liveness
status is monitored. See the details
of this statistical data collection method. As in Object Allocation profiling, it is advised that
only a small proportion of objects, say 1 out of 10 or 1 out of 20, is tracked
in order to keep both temporal and spatial overhead under control. The proportion
of objects that are tracked can be changed in Analyze Memory Usage command dialog,
or if you perform Custom Memory Profiling.
- Tracked allocated objects
This is the total number of tracked objects that have been allocated.
- Average object age
This is the average age for the tracked live objects of this class. The age
of the object is measured as the number of garbage collections (GCs) that
this object has survived. If generational garbage collector (which is default
for the HotSpot JVM) is used, Profiler currently does not distinguish between
partial (young generation) and full garbage collections. Average age is
the sum of ages for all objects divided by the number of objects.
- Number of survived generations
This metrics for objects of a particular class is calculated in a
complex way. In essence, it represents the total number of different
object ages for objects of this class. If this number keeps growing steadily
for a class, it is usually the sign of a memory leak. This is because a
memory leak, or at least the most dangerous kind of memory leak, is a situation
when objects for some class are allocated all the time, but at best collected
only partially. By obtaining a reverse call graph for a leaking class you
can determine which allocation site has the largest number of surviving
generations that is, which one generates most or all of the leaking
objects. Knowing where an object has been allocated can, in turn, often
help to identify the reason for a memory leak.
- Total number of allocated objects
The total number of allocated objects for this class. This number is the
same number you get when you perform object allocation profiling, and
represents the actual total number of objects of the given class that have
ever been allocated.
You can sort classes by any of the above numbers by clicking on the respective
column header or using the local popup menu. You can also choose to stop profiling
certain classes.
To stop profiling for certain classes
When profiling object liveness, you can limit the classes you are profiling.
You can right-click on a class to open the contextual menu which gives you the option
to either stop profiling the selected class or all classes listed below the selected class.
This option is useful when you are profiling an application
with a large number of classes and you have already figured out which classes
you are interested in (for example, the longest living or the leaking ones).
In this situation, it often makes sense to avoid unnecessary runtime overhead
(which may be quite high) by stopping profiling for all other classes.
How Profiler tracks object liveness
Profiler keeps track of the liveness status of only those objects whose
allocation it previously registered. That is, it does not make heap snapshots
like some other tools. Instead, it internally associates Java WeakReferences
with objects that it registered allocated. If you started object liveness profiling
in the middle of program execution, or if you invoke the Profile > Reset
Collected Results
while
profiling is active, it is likely that you will
not see all of the live objects that are on the heap of your target VM. However,
when solving the most important problems that object liveness profiling addresses
- allocating too many objects over time, and memory leaks - this
is not a serious issue. In these situations it is more important to see how
many objects the application allocates and garbage collects currently, rather
than how many have been allocated long ago, perhaps even at application startup
time.
Object Allocation Results
When you profile object allocation, the Profiling Results tab displays a list of classes
(including array classes), with the total size and number of instances that have
been allocated since you issued the instrumentation command.
(Click here for
an example of the Profiling Results for object allocation.)
Once you enable Object Allocation profiling, all classes
currently loaded by the target JVM (and each new class as it is loaded) are instrumented to produce
information about object allocations.
The number of object allocations that Profiler presents is exact, whereas
both the total object size and the reverse call graphs are by default
obtained statistically. For more information about how Profiler does this, see
Semi-statistical data collection in Memory Profiling.
Using the Results: A Leaking Application
Below, we show a demonstration of a leaking application in which we initially identify
the instances of the class String that are leaking. That is because for
despite the relatively small number of the objects themselves, the number of
surviving generations for this class is much larger than for the other types,
and this number is growing constantly:
Then we identify the location in the code where the leaking String
instances, as opposed to "healthy"String instances,
are allocated. (For this location the number of surviving generations is, again,
much higher than for others.)
See also