Skip to content

Commit

Permalink
Add retained size to reports
Browse files Browse the repository at this point in the history
Fixes #162
  • Loading branch information
pyricau committed May 30, 2015
1 parent 5514a1d commit 2b104f0
Show file tree
Hide file tree
Showing 8 changed files with 44 additions and 13 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* 2 new ignored Android SDK leaks: [#26](https://github.com/square/leakcanary/issues/26) [#62](https://github.com/square/leakcanary/issues/62).
* Added excluded leaks to text report [#119](https://github.com/square/leakcanary/issues/119).
* Added LeakCanary SHA to text report [#120](https://github.com/square/leakcanary/issues/120).
* Add retained size to leak reports [#162](https://github.com/square/leakcanary/issues/162).

### Dependencies

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,17 @@
public final class AnalysisResult implements Serializable {

public static AnalysisResult noLeak(long analysisDurationMs) {
return new AnalysisResult(false, false, null, null, null, analysisDurationMs);
return new AnalysisResult(false, false, null, null, null, 0, analysisDurationMs);
}

public static AnalysisResult leakDetected(boolean excludedLeak, String className,
LeakTrace leakTrace, long analysisDurationMs) {
return new AnalysisResult(true, excludedLeak, className, leakTrace, null, analysisDurationMs);
LeakTrace leakTrace, long retainedHeapSize, long analysisDurationMs) {
return new AnalysisResult(true, excludedLeak, className, leakTrace, null, retainedHeapSize,
analysisDurationMs);
}

public static AnalysisResult failure(Exception exception, long analysisDurationMs) {
return new AnalysisResult(false, false, null, null, exception, analysisDurationMs);
return new AnalysisResult(false, false, null, null, exception, 0, analysisDurationMs);
}

/** True if a leak was found in the heap dump. */
Expand All @@ -56,16 +57,23 @@ public static AnalysisResult failure(Exception exception, long analysisDurationM
/** Null unless the analysis failed. */
public final Exception failure;

/**
* The number of bytes which would be freed if all references to the leaking object were
* released. 0 if {@link #leakFound} is false.
*/
public final long retainedHeapSize;

/** Total time spent analyzing the heap. */
public final long analysisDurationMs;

private AnalysisResult(boolean leakFound, boolean excludedLeak, String className,
LeakTrace leakTrace, Exception failure, long analysisDurationMs) {
LeakTrace leakTrace, Exception failure, long retainedHeapSize, long analysisDurationMs) {
this.leakFound = leakFound;
this.excludedLeak = excludedLeak;
this.className = className;
this.leakTrace = leakTrace;
this.failure = failure;
this.retainedHeapSize = retainedHeapSize;
this.analysisDurationMs = analysisDurationMs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,18 @@ public AnalysisResult checkForLeak(File heapDumpFile, String referenceKey) {
return noLeak(since(analysisStartNanoTime));
}

long retainedHeapSize = snapshot.getRetainedHeapSize(leakingRef.getObjectId());

String className = leakingRef.getClazz().getName();

AnalysisResult result =
findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, className, true);
findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, className, retainedHeapSize,
true);

if (!result.leakFound) {
result = findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, className, false);
result =
findLeakTrace(analysisStartNanoTime, snapshot, leakingRef, className, retainedHeapSize,
false);
}

return result;
Expand All @@ -117,7 +122,8 @@ public AnalysisResult checkForLeak(File heapDumpFile, String referenceKey) {
}

private AnalysisResult findLeakTrace(long analysisStartNanoTime, ISnapshot snapshot,
IObject leakingRef, String className, boolean excludingKnownLeaks) throws SnapshotException {
IObject leakingRef, String className, long retainedHeapSize, boolean excludingKnownLeaks)
throws SnapshotException {

ExcludedRefs excludedRefs = excludingKnownLeaks ? this.excludedRefs : baseExcludedRefs;

Expand All @@ -130,7 +136,8 @@ private AnalysisResult findLeakTrace(long analysisStartNanoTime, ISnapshot snaps

LeakTrace leakTrace = buildLeakTrace(snapshot, gcRootsTree, excludedRefs);

return leakDetected(!excludingKnownLeaks, className, leakTrace, since(analysisStartNanoTime));
return leakDetected(!excludingKnownLeaks, className, leakTrace, retainedHeapSize,
since(analysisStartNanoTime));
}

private ISnapshot openSnapshot(File heapDumpFile) throws SnapshotException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import static com.squareup.leakcanary.LeakCanary.leakInfo;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.classSimpleName;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.findNextAvailableHprofFile;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.humanReadableByteCount;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.leakResultFile;

/**
Expand Down Expand Up @@ -100,7 +101,8 @@ protected final void onHeapAnalyzed(HeapDump heapDump, AnalysisResult result) {
String contentTitle;
if (result.failure == null) {
contentTitle =
getString(R.string.__leak_canary_class_has_leaked, classSimpleName(result.className));
getString(R.string.__leak_canary_class_has_leaked, classSimpleName(result.className),
humanReadableByteCount(result.retainedHeapSize));
} else {
contentTitle = getString(R.string.__leak_canary_analysis_failed);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.squareup.leakcanary.internal.DisplayLeakActivity;
import com.squareup.leakcanary.internal.HeapAnalyzerService;

import static com.squareup.leakcanary.internal.LeakCanaryInternals.humanReadableByteCount;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.isInServiceProcess;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.setEnabled;

Expand Down Expand Up @@ -96,6 +97,7 @@ public static String leakInfo(Context context, HeapDump heapDump, AnalysisResult
info += " (" + heapDump.referenceName + ")";
}
info += " has leaked:\n" + result.leakTrace.toString() + "\n";
info += "* Retaining: " + humanReadableByteCount(result.retainedHeapSize) + ".\n";
if (detailed) {
detailedString = "\n* Details:\n" + result.leakTrace.toDetailedString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import static android.view.View.VISIBLE;
import static com.squareup.leakcanary.LeakCanary.leakInfo;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.detectedLeakDirectory;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.humanReadableByteCount;
import static com.squareup.leakcanary.internal.LeakCanaryInternals.leakResultFile;

@SuppressWarnings("ConstantConditions") @TargetApi(Build.VERSION_CODES.HONEYCOMB)
Expand Down Expand Up @@ -252,7 +253,8 @@ public void onItemClick(AdapterView<?> parent, View view, int position, long id)
HeapDump heapDump = visibleLeak.heapDump;
adapter.update(result.leakTrace, heapDump.referenceKey, heapDump.referenceName);
setTitle(
getString(R.string.__leak_canary_class_has_leaked, classSimpleName(result.className)));
getString(R.string.__leak_canary_class_has_leaked, classSimpleName(result.className),
humanReadableByteCount(result.retainedHeapSize)));
}
} else {
if (listAdapter instanceof LeakListAdapter) {
Expand Down Expand Up @@ -333,7 +335,8 @@ class LeakListAdapter extends BaseAdapter {
String title;
if (leak.result.failure == null) {
title = index + getString(R.string.__leak_canary_class_has_leaked,
classSimpleName(leak.result.className));
classSimpleName(leak.result.className),
humanReadableByteCount(leak.result.retainedHeapSize));
} else {
title = index
+ leak.result.failure.getClass().getSimpleName()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ public static void setEnabled(Context context, final Class<?> componentClass,
});
}

/** Based on http://stackoverflow.com/a/3758880. */
public static String humanReadableByteCount(long bytes) {
if (bytes < 1024) return bytes + " B";
int exp = (int) (Math.log(bytes) / Math.log(1024));
String pre = "KMGTPE".charAt(exp - 1) + "";
return String.format("%.1f %sB", bytes / Math.pow(1024, exp), pre);
}

public static boolean isInServiceProcess(Context context, Class<? extends Service> serviceClass) {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
-->
<resources>

<string name="__leak_canary_class_has_leaked">%s has leaked</string>
<string name="__leak_canary_class_has_leaked">%1$s has leaked %2$s</string>
<string name="__leak_canary_analysis_failed">Leak analysis failed</string>
<string name="__leak_canary_leak_list_title">Leaks in %s</string>
<string name="__leak_canary_notification_message">Click for more details</string>
Expand Down

0 comments on commit 2b104f0

Please sign in to comment.