private Instance findLeakingReference(String key, Snapshot snapshot) { ClassObj refClass = snapshot.findClass(KeyedWeakReference.class.getName()); List<String> keysFound = new ArrayList<>(); for (Instance instance : refClass.getInstancesList()) { List<ClassInstance.FieldValue> values = classInstanceValues(instance); String keyCandidate = asString(fieldValue(values, "key")); if (keyCandidate.equals(key)) { return fieldValue(values, "referent"); } keysFound.add(keyCandidate); } throw new IllegalStateException( "Could not find weak reference with key " + key + " in " + keysFound); }
/** * Bitmaps and bitmap byte arrays are sometimes held by native gc roots, so they aren't included * in the retained size because their root dominator is a native gc root. To fix this, we check if * the leaking instance is a dominator for each bitmap instance and then add the bitmap size. * * <p>From experience, we've found that bitmap created in code (Bitmap.createBitmap()) are * correctly accounted for, however bitmaps set in layouts are not. */ private int computeIgnoredBitmapRetainedSize(Snapshot snapshot, Instance leakingInstance) { int bitmapRetainedSize = 0; ClassObj bitmapClass = snapshot.findClass("android.graphics.Bitmap"); for (Instance bitmapInstance : bitmapClass.getInstancesList()) { if (isIgnoredDominator(leakingInstance, bitmapInstance)) { ArrayInstance mBufferInstance = fieldValue(classInstanceValues(bitmapInstance), "mBuffer"); // Native bitmaps have mBuffer set to null. We sadly can't account for them. if (mBufferInstance == null) { continue; } long bufferSize = mBufferInstance.getTotalRetainedSize(); long bitmapSize = bitmapInstance.getTotalRetainedSize(); // Sometimes the size of the buffer isn't accounted for in the bitmap retained size. Since // the buffer is large, it's easy to detect by checking for bitmap size < buffer size. if (bitmapSize < bufferSize) { bitmapSize += bufferSize; } bitmapRetainedSize += bitmapSize; } } return bitmapRetainedSize; }