- YourKit
-
Add
Thread.sleep(60000)
to the START and END of the method you want to profile.If you're profiling an async method (e.g.
Future
/Task
/ConnectionIO
), put the END in a finalflatMap
to ensure the results from all previous continuations remain in memory. -
Add a
println(obj)
after the lastThread.sleep(60000)
for each object you want to measure. This ensures the object is not GC'd before you take the snapshot. This can occur (possibly as ascalac
optimisation) when a local variablex
is in-scope, but is not used by any subsequent calls. This behaviour has been observed to happen inside for-comprehensions (e.g.for { a <- fooA(); b <- fooB(a); c <- fooC(); } yield()
-- in this example if you paused onc <- fooC()
thena
andb
may be GC'd). So it's important you use the objects AFTER theThread.sleep()
where you're taking the snapshot. -
Run your application, and attach YourKit.
-
Navigate to the
Memory
section. -
Wait for 1st
Thread.sleep
(start of method). -
Click
Advance Object Generation Number
in YourKit. -
Wait for 2nd
Thread.sleep
(end of method). -
Click
Capture Memory Snapshot
in YourKit. -
Open the snapshot.
-
Navigate to
Objects by Category
>Reachability
>[Green] Objects reachable ... via strong references
> Right-click >Selected Objects
-
Then navigate to:
Objects by Category
>Generation
> Last Item in List > Right-click >Selected Objects
.This will now display all non-GCd objects created while this method was running.
-
Keep clicking 'Calculate Retained Size' until the objects sizes have been calculated.
-
Total memory used by this method (excluding memory that's been GC'd):
- See total
shallow size
in the top-left corner. This represents # of bytes allocated since this method began executing.
- See total
-
Size of an object
-
Navigate to
Objects by Category
>Class
and find your class. -
Select class > Right-click >
Selected Objects
. -
This will show you the individual instances of that type (and their heirarchical memory usage).
-
-
Largest objects
-
Approach 1: navigate to
Objects by Category
>Biggest Objects
and expand the top-level items. -
Approach 2: navigate to
Objects by Category
>Class
and sort byshallow size
descending (note:retained size
can be useful for complex objects, but BEWARE as the sizes overlap, and do not necessarily represent memory allocated during this method's execution, e.g. a reference to a large pre-existing object, e.g. from a cache, will bloat the retained size).
-
-
When you click
Advance Object Generation Number
YourKit marks all objects currently in the heap as being generationN
. If you click the button again, all new objects created since then will be marked as generationN+1
, and so on. It's a way of dividing the heap into time slices, so that when you're analysing the heap, you can look only at the objects created during the execution of a method, rather than all the objects on the heap (most of which will have been present before your method was called). -
When you click
Capture Memory Snapshot
YourKit captures all the objects in the heap at that instant in time (i.e. it does not capture some cumulative set of all objects created from the start of the application). -
It's IMPORTANT to click
Capture Memory Snapshot
while your method's stack frame still exists. If you click after the method completes, YourKit won't capture sufficient information to correctly calculate the "retained sizes" of the objects that were created while the method was executing, as some/all of those objects may be GC'd. -
Snapshots record both "used" and "unused" objects, where the latter are ready for garbage-collection.
You can manually force a GC before performing the snapshot, which will remove the majority of the "noise" from the snapshot.
To avoid having to do this, however, YourKit allows you to filter-our GC-able objects via their "reachability" filter (used above).