Activity Memory leak scenario

1. Set the Context or View to static

2. Various listeners are not unregistered. (Various system listeners, such as broadcasts, may be registered in an Activity.)

3. Non-static handlers cause Activity leaks. (Generally, you want to make it static and hold a weak reference to the Activity internally to avoid memory leaks.)

4. Tripartite libraries use Context. Change the context passed in to a static static type in the tripartite library. This kind of situation is a kind of invisible Activity leak, it is difficult to detect in our own projects, so usually in the development process, try to use the Context. GetApplicationContext, don’t directly pass the Activity to other components.

Ii. How to detect memory leaks

WeakReference in Java is a WeakReference type, and whenever GC occurs, the object it holds is reclaimed if it is not held by another strong reference

Implementation approach

The core principle of LeakCanary memory leak detection is implemented based on WeakReference and ReferenceQueue.

When an Activity needs to be reclaimed, it is wrapped in a WeakReference, and a custom ReferenceQueue is passed in the WeakReference constructor.

Then make a mark Key for the wrapped WeakReference, and add the corresponding Key record in a strong reference Set

Finally, GC is actively triggered to traverse all records in the custom ReferenceQueue and delete the records in the Set according to the obtained Reference object

After the previous three steps, objects that should be collected by GC but are still in memory are the ones that leak.

Source code analysis

As normal, when an Activity calls onDestroy, the Activity is already useless. So we need to listen for calls to the onDestroy method on each Activity.

LeakCanary monitoring the Activity in the life cycle is responsible by ActivityRefWatch, mainly by registering the Android system provides ActivityLifecycleCallbacks, To listen for calls to the Activity’s lifecycle methods

When listening on the Activity’s onDestroy method, it is passed to the RefWatcher watch method

RefWatcher is a core class for LeakCanary that detects if an object is leaking memory. The main implementation is in the Watch method

1. Generate a random string key to identify WeakReference

2. Package the detected object into a WeakReference, and use key;

3. Call ensureGoneAsync to start the detection.

EnsureGoneAsync () executes an overloaded method, ensureGone, via WatchExecutor.

Memory leak detection is implemented in ensureGone

1. Go through all the elements in ReferenceQueue and delete the elements in the set retainedKeys according to the key in each element.

2. Determine if the collection retainedKeys still contains weak references to the detected object. If it does, the detected object has not been reclaimed, which is a memory leak.

3. Generate Heap information and a memory leak analysis report and report it to program developers.

The implementation principle of LeakCanary is actually fairly simple, but there are a few other details worth noting about the internal implementation.

Memory leak detection timing

This memory leak detection and analysis is performance-intensive, so LeakCanary has also made some optimizations to minimize the impact on UI thread rendering. The WatchExecutor’s execute method is called in the ensureGoneAsync method to perform the check operation

The IdleHandler is inserted into the main thread MessageQueue. The IdleHandler is pulled from the queue and executed by Looper only when the main thread is idle. Therefore, memory detection can effectively avoid taking up UI rendering time.

AddIdleHandler is also often used to optimize App startup, such as in the onCreate method of the Application to initialize the 3-way library. You can speed up the Application startup process by placing initialization operations for lower-priority, temporarily unused 3-way libraries into IdleHandler. I think the method name addIdleMessage would be more appropriate, since MessageQueue inserts only Message objects.

Special type adaptation

Some special models of the system have memory leaks that prevent activities from being reclaimed, so you need to exclude these cases when detecting memory leaks. In the LeakCanary initialization method install, a series of scenarios to ignore are specified through the excludedRefs method. These scenarios are enumerated in AndroidExcludedRefs

LeakCanary How do I detect other classes

LeakCanary can only detect Activity leaks by default, but RefWatcher’s Watch method passes in Object, so it can theoretically detect any class. LeakCanary’s install method returns a RefWatcher object, we just need to save the RefWatch object in the Application and pass the object to be detected to the Watch method.