- System requirements
- Profiler architecture
- Running the profiler
- Profiler activation
- Start profiling
- Connect to profiled application
- Capturing snapshots
- Solving performance problems
- CPU profiling
- Threads
- Memory profiling
- Garbage collection
- Exception profiling
- Probes: monitor higher level events
- Performance Charts
- Inspections: automatic recognition of typical problems
- Automatically trigger actions on event
- Summary, snapshot annotation, automatic deobfuscation
- Time measurement (CPU time, wall time)
- Filters
- Snapshot directory customization
- Export of profiling results to HTML, CSV, XML, plain text
- Profiler API
- Profiler HTTP API
- Command line tool to control profiling
- Settings
Memory leaks
What is a memory leak?
Memory leak is an existence of objects that are not needed anymore according to the application logic,
but still retain memory and cannot be collected because they are referenced from other live objects,
due to a bug in application itself.
Obviously, each leaked object is accessible from at least one GC root or represents a GC root.
In other words, for each leaked object there is always a path that starts from GC root(s) and contains (ends with) the leaked object.
How to find memory leaks?
1. Detect memory leak, i.e. understand what objects do exist while they should not.
If you do not know yet what objects are leaked, YourKit Profiler can help you find out.
You can suspect the presence of memory leaks with the help of the memory telemetry, by watching how used memory grows. You can use Force Garbage Collection to immediately see whether some of the objects that consume the memory can be collected, thus decreasing used memory. If after 2-3 explicit garbage collections the used memory remains on the same level or decreases insignificantly, this possibly means you have a leak. ("Possibly," because it can turn out not to be a leak, but simply high memory consumption -- Learn how to deal with that case)
To detect a memory leak, use the following scenario:
- Connect to profiled application
- Capture memory snapshot just before executing the task which is suspected to cause leak.
- Let the application perform the task.
- Capture memory snapshot and open it.
- Compare memory snapshots to see objects created during the task execution; leaked objects should be among them.
You can also analyze a single snapshot, with the help of objects view.
Often, potential leaks in particular profiled application are well known in advance, i.e. you know a class of objects that have a "tendency" to leak while application is being developed, changed, refactored. You can easily check for the presence of such objects, with the help of Memory | Instances by Class... (Ctrl+N).
Note that even one class can have objects legally and illegally (leaked objects) retained in memory.
To distinguish between them, you can use objects explorer to see outgoing and/or incoming references. For example,
an object may have a String
field with the value that can identify this object among other objects of the same type.
2. Once you have found leaked object(s), it's time to understand why they are retained in memory
Select the leaked object(s) in a memory view, and use Memory | Paths from GC Roots... (Ctrl+P). See Working with paths for details.
Let us look at a simple example of how to use paths.
Assume that we are profiling an Editor application that can open, edit and close text files. There is a singleton object that acts as a manager of opened files, and the data of each opened file is represented with an instance of class Document.
During the profiling session we open several text files, edit them, close them and take a memory snapshot.
If everything is correct, there should be no instances of Document that cannot be collected. So, first of all, we use Memory | Instances by Class... (Ctrl+N), to see if there are leaked Documents.
Assume we have found such objects - so we do have a leak. There should be paths from GC roots to these objects (or, perhaps, some of them may belong to GC roots themselves - this will be indicated in the view).
Thus we search for the paths from GC roots to one of the Documents (Ctrl+P), or to all Documents defining
the set.
If all the paths go through the manager singleton, the code responsible for closing files in our editor must have a bug.
If none of the paths contains the manager singleton, then the closing operation works correctly, but there are object(s)
in the path(s) that erroneously hold references to Documents and cause the memory leak.
Browsing paths, use navigation feature of IDE integration.