OOM is a common problem in Android development, and memory leaks are often the culprit. In order to detect memory leaks simply and conveniently, Square has open-sourced LeakCanary, which can monitor whether an Activity has a leak in real time. Once a leak is found, it will automatically pop up a prompt and related leak information for analysis. The purpose of this article is to explore the Activity leak detection mechanism by analyzing the LeakCanary source code. How to use LeakCanary To introduce LeakCanary into our project, we only need to do the following two steps:
It can be seen that the most critical thing is LeakCanary.install(this); This sentence officially opens the door to LeakCanary. In the future, it will automatically help us detect memory leaks and pop up notification information when a leak occurs. Start with LeakCanary.install(this); Let's take a look at what it does.
First, let’s look at the most important part:
First, a RefWatcher is generated. This thing is very important. As the name suggests, it is used to watch Reference, that is, a tool for monitoring references. Then pass the refWatcher and the application we provide to ActivityRefWatcher.installOnIcsPlus(application, refWatcher);. Continue reading.
An ActivityRefWatcher is created. You should be able to feel that this thing is used to monitor our Activity leakage. It calls the watchActivities() method to start monitoring. The following is the core principle of its monitoring:
It registers an ActivitylifecycleCallbacks callback function in the application, which can be used to monitor the lifecycle events of all Activities in the entire life cycle of the Application. What is this lifecycleCallbacks?
It turns out that it only listens to the onActivityDestroyed events of all Activities. When the Activity is Destoryed, the ActivityRefWatcher.this.onActivityDestroyed(activity); function is called. I guess, under normal circumstances, when an activity is destroyed by this function, the activity object should become null. If it does not become null, it means that a memory leak has occurred. Therefore, we think that this function ActivityRefWatcher.this.onActivityDestroyed(activity); should be used to monitor whether the activity object has become null. Continue to watch.
It can be seen that this function passes the target activity object to RefWatcher, allowing it to monitor whether the activity is recycled normally. If it is not recycled, it means that a memory leak has occurred. How does RefWatcher monitor whether the activity is recycled normally? Let's first take a look at what this RefWatcher is.
There are two new objects involved here: AndroidHeapDumper and AndroidWatchExecutor. The former is used to dump the heap memory status, and the latter is used to watch a reference listener. The specific principle will be seen later. In short, a RefWatcher object has been generated here. Now let's look at refWatcher.watch(activity); called in onActivityDestroyed(Activity activity) above. Let's take a look at this core watch(activity) method to understand how it monitors whether the activity is recycled.
As you can see, it first wraps the activity we passed in into a KeyedWeakReference (which can be temporarily regarded as a normal WeakReference), and then watchExecutor will execute a Runnable, which will call the ensureGone(reference, watchStartNanoTime) function. Before looking at this function, let's guess that we know that the watch function itself is used to monitor whether the activity is recycled normally, which involves two problems:
So we think that what the ensureGone function itself has to do is just as its name suggests, which is to ensure that the reference is recycled, otherwise it means a memory leak. Core function: ensureGone(reference) detection recovery Let's look at this function implementation:
Here we first explain how WeakReference and ReferenceQueue work. 1. WeakReference Strongly referenced objects will never be reclaimed by the garbage collector even if OOM occurs; weakly referenced objects will be reclaimed immediately once they are discovered by the garbage collector; softly referenced objects are memory-sensitive and will only be reclaimed when memory is insufficient, and are often used as memory-sensitive caches; phantom references may be reclaimed at any time and are less commonly used. 2. ReferenceQueue We often use a WeakReference<Activity> reference = new WeakReference(activity);, where we create a reference to a certain activity. When the activity is garbage collected, the reference will be put into the internal ReferenceQueue. In other words, all references taken from the queue ReferenceQueue, the real objects they point to have been successfully recycled. Then go back to the code above. When an activity is passed to RefWatcher, a unique key corresponding to the activity is created and stored in a collection retainedKeys. In other words, all the unique keys corresponding to the activities we want to observe will be put into the retainedKeys collection. Based on our understanding of ReferenceQueue, as long as all references in the queue are taken out and the keys in the corresponding retainedKeys are removed, the objects corresponding to the remaining keys will not be recycled.
At this point, we have finished looking at the core memory leak detection mechanism. Memory leak detection summary From the above, we have a general understanding of the memory leak detection mechanism, which is roughly the following steps:
Explore some interesting questions about LeakCanary After studying the source code of LeakCanary, I would like to raise a few more interesting questions for discussion. Why is the LeakCanary project directory structure divided like this? The following is the entire LeakCanary project structure: For developers, they only need to use LeakCanary.install(this);. Why is the entire project divided into so many modules? In fact, each module here has its own role.
When an Activity is destroyed, how long does it take for LeakCanary to check for leaks? As can be seen in the source code, LeakCanary does not check immediately after destruction, but lets an AndroidWatchExecutor do the check. What does it do?
As you can see, it first adds an IdleHandler to the main thread's MessageQueue. What is IdleHandler? We know that Looper will continuously take out Message from MessageQueue and execute it. When there is no new Message to execute, Looper enters the Idle state and takes out IdleHandler to execute. In other words, IdleHandler is a message with a lower priority, which is only processed when Looper has no messages to process. Moreover, if the internal queueIdle() method returns true, it means that the task is always alive and will be executed every time Looper enters Idle; otherwise, if it returns false, it means that it will only be executed once and discarded after execution. So, what is this lower priority task? backgroundHandler.postDelayed(runnable, delayMillis); , runnable is the previous ensureGone(). That is to say, when the main thread is idle and has nothing to do, it starts sending a delayed message to the background thread, telling the background thread to start checking whether the Activity has been recycled after 5s (delayMillis). Therefore, when an Activity is destroyed, it must first wait until the main thread is idle, and then delay for 5 seconds (delayMillis) before starting the leak check. Knowledge points: 1. How to create a low-priority main thread task that will only execute when the main thread is idle and will not affect the performance of the app?
2. How to quickly create a main/sub-thread handler?
3. How to quickly determine whether the current thread is running?
Can System.gc() trigger an immediate GC? If not, how can I trigger an immediate GC? In LeakCanary, it is necessary to trigger GC immediately and then determine whether the weak reference is recycled immediately. This means that the GC must be able to be executed synchronously immediately. The commonly used method to trigger GC is System.gc(), but can it meet our requirements? Let's look at how it is implemented:
The comments clearly state that System.gc() only suggests that the garbage collector should perform collection, but it cannot guarantee that it will actually be collected. It can also be seen from the code that you must first determine shouldRunGC before deciding whether to actually perform GC. Knowledge points: So how to implement real-time GC? LeakCanary refers to a piece of AOSP code
How can LeakCanary be modified? Ignore certain classes or activities that are known to leak LeakCanary provides an ExcludedRefs class, to which you can add some actively ignored classes. For example, if there are some memory leaks in the Android source code that are not leaks in our App, then we can exclude them. In addition, if you do not want to monitor some special Activities, you can filter out the special Activities in onActivityDestroyed(Activity activity) and only call refWatcher.watch(activity) to monitor other Activities. Upload memory leak data to the server LeakCanary provides AbstractAnalysisResultService, which is an intentService. The received intent contains HeapDump data and AnalysisResult results. As long as we inherit this class and implement our own listenerServiceClass, we can upload the heap data and analysis results to our own server. summary This article analyzes the principle of LeakCanary through source code, raises some interesting questions, and learns some practical knowledge points. I hope it will be inspiring to readers, and you are welcome to discuss with me. We will continue to select high-quality open source projects for analysis, and welcome your comments. |
>>: A brief analysis of the HTTPS principle and its use in Android
When it comes to hot products, what do you think ...
Recently, according to Reuters, litigation manage...
introduction Starting today, the "Treasures ...
Produced by: Science Popularization China Produce...
Meat, as an important component of the human diet...
The second phase of the advanced watercolor illus...
Practice meditation with Qian Wei (Qian Wei) Intr...
The Classic of Mountains and Seas records: "...
Mixed Knowledge Specially designed to cure confus...
【3Dmax】LM Ranger Advanced Animation Full Process C...
[[330468]] Currently, from mobile phone manufactu...
(1). It seems that your keyword quality is less t...
According to ZDNet, Apple's iPad tablet sales...
Event planning refers to the planning of differen...
Review expert: Peng Guoqiu, deputy chief physicia...