square / leakcanary

A memory leak detection library for Android.

Home Page:https://square.github.io/leakcanary

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support computing retained size for any object

pyricau opened this issue · comments

When LeakCanary traverses the graph to find shortest paths to GC Roots, it has an option to also compute retained sizes for nodes in those paths. When that option is turned on, LeakCanary will traverse the entire graph (instead of bailing early once its found all leaking instances).

The graph traversal creates a DominatorTree object, used here to compute retained size:

return dominatorTree.computeRetainedSizes(nodeObjectIds) { objectId ->

I just re read the DominatorTree code and took notes

This is a destructive way of computing the retained size.
The idea is that we’re going through all objects in the heap. For each object we know its direct dominator, however, we don’t really care about that
we really care about the closest dominator in the dominator chain that also belongs to the set of objects for which we’re trying to compute retained size
that set if a very small set of objects (edited)
so we essentially updating the dominator map, instead of being object => dominator, it becomes “object => dominator we’re interested in for retained size, or nothing”
so as we go through the entire map we also recursively for each entry have to go through parent dominators, but the destructive update makes it so that over time we tend to have to do less of that

We could change this to:

  • Make that code operate on a copy of the Map<Long, Long> instead of destructing the original
  • Move DominatorTree into HeapGraph graph context (basically a cache)

That would allow us to compute retained size for any other object, after LeakCanary has done its traversal. One benefit is that we can then plug in whatever shallow size computation method we want.

However, it's a bit of a waste because we're re traversing dominators every time.

Alternatively we could compute retained size for all dominators, and store that instead.