- 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.
-
Then either:
-
For the largest object(s): Navigate to
Objects by Category
>Biggest Objects
and expand the top-level items.This reveals the largest objects in a non-overlapping way. I.e. each object is only retained by one object in this view (probably the object that was first to ever reference it), so if an object is shared among many other objects, you won't see that object's size bloating the 'retained size' of many objects, like you would in the
Class
view. -
For a specific type: 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),
-
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).