LeakCanary use
In Application onCreate, do the following
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
// Normal app init code...
Copy the code
1.LeakCanary.isInAnalyzerProcess(this)
Check whether the current process is in the same process as HeapAnalyzerService
* Whether the current process is the process running the {@link HeapAnalyzerService}, which is
* a different process than the normal app process.
*/
public static boolean isInAnalyzerProcess(Context context) {
return isInServiceProcess(context, HeapAnalyzerService.class);
}
Copy the code
2.LeakCanary.install(this);
public static RefWatcher install(Application application) {
return refWatcher(application).listenerServiceClass(DisplayLeakService.class)
.excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
.buildAndInstall();
}
Copy the code
refWatcher(application)
Returns an AndroidRefWatcherBuilder extends RefWatcherBuilder object
/** Builder to create a customized {@link RefWatcher} with appropriate Android defaults. */
public static AndroidRefWatcherBuilder refWatcher(Context context) {
return new AndroidRefWatcherBuilder(context);
}
Copy the code
The following are the AndroidRefWatcherBuilder. In Java
.listenerServiceClass(DisplayLeakService.class)
/**
* Sets a custom {@link AbstractAnalysisResultService} to listen to analysis results. This
* overrides any call to {@link #heapDumpListener(HeapDump.Listener)}.
*/
public AndroidRefWatcherBuilder listenerServiceClass(
Class<? extends AbstractAnalysisResultService> listenerServiceClass) {
return heapDumpListener(new ServiceHeapDumpListener(context, listenerServiceClass));
}
Copy the code
-
DisplayLeakService extends AbstractAnalysisResultService extends IntentService dump information for leak after the show
-
Create a ServiceHeapDumpListener object as a heapDumpListener
2.. excludedRefs(AndroidExcludedRefs.createAppDefaults().build())
ExcludedRefs excluded references? AndroidExcludedRefs. CreateAppDefaults (). The build () to create a ExcludedRefs RefWatcherBuilder object
/**
* This returns the references in the leak path that can be ignored for app developers. This
* doesn't mean there is no memory leak, to the contrary. However, some leaks are caused by bugs * in AOSP or manufacturer forks of AOSP. In such cases, there is very little we can do as app * developers except by resorting to serious hacks, so we remove the noise caused by those leaks. */ public static ExcludedRefs.Builder createAppDefaults() { return createBuilder(EnumSet.allOf(AndroidExcludedRefs.class)); }Copy the code
3 .buildAndInstall();
/**
* Creates a {@link RefWatcher} instance and starts watching activity references (on ICS+).
*/
public RefWatcher buildAndInstall() {
RefWatcher refWatcher = build();
if(refWatcher ! = DISABLED) { LeakCanary.enableDisplayLeakActivity(context); ActivityRefWatcher.install((Application) context, refWatcher); }return refWatcher;
}
Copy the code
- Create the RefWatcher object
- enableDisplayLeakActivity(context)
- ActivityRefWatcher.install((Application) context, refWatcher)
enableDisplayLeakActivity(context)
public static void enableDisplayLeakActivity(Context context) {
setEnabled(context, DisplayLeakActivity.class, true);
}
Copy the code
DisplayLeakActivity Displays the dump Activity
public static void setEnabled(Context context, final Class<? > componentClass, final boolean enabled) { final Context appContext = context.getApplicationContext(); executeOnFileIoThread(newRunnable() {
@Override public void run() {
setEnabledBlocking(appContext, componentClass, enabled); }}); }Copy the code
executeOnFileIoThread
public static void executeOnFileIoThread(Runnable runnable) {
fileIoExecutor.execute(runnable);
}
Copy the code
private static final Executor fileIoExecutor = newSingleThreadExecutor(“File-IO”); Is a single-threaded thread pool executing setEnabledBlocking(), freezing the application
public static void setEnabledBlocking(Context appContext, Class<? > componentClass, boolean enabled) { ComponentName component = new ComponentName(appContext, componentClass); PackageManager packageManager = appContext.getPackageManager(); int newState = enabled ? COMPONENT_ENABLED_STATE_ENABLED : COMPONENT_ENABLED_STATE_DISABLED; // Blocks on IPC. packageManager.setComponentEnabledSetting(component, newState, DONT_KILL_APP); }Copy the code
Analysis of Android application freezing process
ActivityRefWatcher.install((Application) context, refWatcher)
public static void install(Application application, RefWatcher refWatcher) {
new ActivityRefWatcher(application, refWatcher).watchActivities();
}
Copy the code
ActivityRefWatcher#watchActivities()
ActivityRefWatcher.java
public void watchActivities() {
// Make sure you don't get installed twice. stopWatchingActivities(); / / to avoid repetition and install the application. RegisterActivityLifecycleCallbacks (lifecycleCallbacks); }Copy the code
application.registerActivityLifecycleCallbacks(lifecycleCallbacks);
LifecycleCallbacks is a member variable in ActivityRefWatcher, which is worth noting
ActivityRefWatcher.java
@Override public void onActivityDestroyed(Activity activity) {
ActivityRefWatcher.this.onActivityDestroyed(activity);
}
Copy the code
Continue with the code
void onActivityDestroyed(Activity activity) {
refWatcher.watch(activity);
}
Copy the code
RefWatcher.java
public void watch(Object watchedReference) {
watch(watchedReference, "");
}
Copy the code
public void watch(Object watchedReference, String referenceName) {
if (this == DISABLED) {
return;
}
checkNotNull(watchedReference, "watchedReference");
checkNotNull(referenceName, "referenceName"); final long watchStartNanoTime = System.nanoTime(); String key = UUID.randomUUID().toString(); retainedKeys.add(key); final KeyedWeakReference reference = new KeyedWeakReference(watchedReference, key, referenceName, queue); //1 ensureGoneAsync(watchStartNanoTime, reference); / / 2}Copy the code
final KeyedWeakReference reference =new KeyedWeakReference(watchedReference, key, referenceName, queue)
KeyedWeakReference inherits weak reference, and the constructor passes in watchedReference, referenceName, and key. WatchedReference is an Activity object that monitors deStory, referenceName = “”, and key is randomly generated
System.nanotime () returns nanoseconds, nanoTime can return arbitrary times, or even negative numbers
ensureGoneAsync(watchStartNanoTime, reference)
private void ensureGoneAsync(final long watchStartNanoTime, final KeyedWeakReference reference) {
watchExecutor.execute(new Retryable() {
@Override public Retryable.Result run() {
returnensureGone(reference, watchStartNanoTime); }}); }Copy the code
watchExecutor
The watchExecutor is passed in from the RefWatcher constructor
RefWatcherBuilder.java
#build()
public final RefWatcher build() {
WatchExecutor watchExecutor = this.watchExecutor;
if (watchExecutor == null) {
watchExecutor = defaultWatchExecutor();
}
return new RefWatcher(watchExecutor, debuggerControl, gcTrigger, heapDumper, heapDumpListener,
excludedRefs);
}
Copy the code
#watchExecutor()
/** @see WatchExecutor */
public final T watchExecutor(WatchExecutor watchExecutor) {
this.watchExecutor = watchExecutor;
return self();
}
Copy the code
AndroidRefWatcherBuilder.java
public AndroidRefWatcherBuilder watchDelay(long delay, TimeUnit unit) {
return watchExecutor(new AndroidWatchExecutor(unit.toMillis(delay)));
}
Copy the code
@Override protected WatchExecutor defaultWatchExecutor() {
return new AndroidWatchExecutor(DEFAULT_WATCH_DELAY_MILLIS);
}
Copy the code
The watchExecutor object is an AndroidWatchExecutor, DEFAULT_WATCH_DELAY_MILLIS = 5s
AndroidWatchExecutor.java
@Override public void execute(Retryable retryable) {
if (Looper.getMainLooper().getThread() == Thread.currentThread()) {
waitForIdle(retryable, 0);
} else{ postWaitForIdle(retryable, 0); }}Copy the code
If you’re on the main thread
ensureGone(reference, watchStartNanoTime)
- Two removeWeaklyReachableReferences ()
- gcTrigger.runGc()
- heapdumpListener.analyze()
@SuppressWarnings("ReferenceEquality") // Explicitly checking for named null.
Retryable.Result ensureGone(final KeyedWeakReference reference, final long watchStartNanoTime) {
long gcStartNanoTime = System.nanoTime();
long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
removeWeaklyReachableReferences();
if (debuggerControl.isDebuggerAttached()) {
// The debugger can create false leaks.
return RETRY;
}
if (gone(reference)) {
return DONE;
}
gcTrigger.runGc();
removeWeaklyReachableReferences();
if(! gone(reference)) { long startDumpHeap = System.nanoTime(); long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime); File heapDumpFile = heapDumper.dumpHeap();if (heapDumpFile == RETRY_LATER) {
// Could not dump the heap.
return RETRY;
}
long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap);
heapdumpListener.analyze(
new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs,
gcDurationMs, heapDumpDurationMs));
}
return DONE;
}
Copy the code
removeWeaklyReachableReferences()
private void removeWeaklyReachableReferences() {
// WeakReferences are enqueued as soon as the object to which they point to becomes weakly
// reachable. This is before finalization or garbage collection has actually happened.
KeyedWeakReference ref;
while ((ref = (KeyedWeakReference) queue.poll()) != null) {
retainedKeys.remove(ref.key);
}
}
Copy the code
gcTrigger.runGc()
public void runGc() {
// System.gc() does not garbage collect every time. Runtime.gc() is
// more likely to perfom a gc.
Runtime.getRuntime().gc();
enqueueReferences();
System.runFinalization();
}
Copy the code
ServiceHeapDumpListener.java
@Override public void analyze(HeapDump heapDump) {
checkNotNull(heapDump, "heapDump");
HeapAnalyzerService.runAnalysis(context, heapDump, listenerServiceClass);
}
Copy the code
RefWatcher is a reference observer object that monitors the reference status of the current instance object