The opening

One day, backstage statistics to a large number of OOM collapse online, xiao Wang received the boss’s urgent instructions, immediately investigation!

Wang thought, this is not simple, wait for me to see the crash stack, minutes to solve.

So Xiao Wang unhurried to open the crash background, a look stunned, the same OOM, but there are dozens of different stacks, large to create a View, small to new a String.

Wang almost scolded out: this OOM does not speak wu de ah!

After scolding, I still have to solve the problem, otherwise how can I face the boss

journey

Frustrated, Wang suddenly remembered that he had read a performance optimization article about Profiler integration in Android Studio that could analyze APP memory

Since there’s nothing wrong with the stack, we’ll just take our chances, right

So Wang clicked on the unremarkable “Profiler” panel at the bottom of the IDE and saw

As soon as Wang saw the MEMORY column, it was MEMORY usage

Well, the data is quite complete, but how to know where caused OOM ah, wang began to doubt life…

“You can’t see anything if you don’t move it. Memory is dynamically allocated.”

Wang thought, since there are so many OOM, it must be caused by the common pages in the APP, so Wang began to switch back and forth between the common pages, while observing the trend of memory

After several attempts, Wang found that the application’s memory footprint did increase and remained high even after manual GC

Wang remembered that “objects that cannot be collected by GC will cause memory leaks” in the interview book, so he clicked GC manually to avoid inaccurate data

The Java heap went from 15.7MB to 19.3MB, which didn’t seem like a big deal, while Native went from 56.1MB to 97.5MB, which is a 40MB+ increase in minutes

Xiao Wang was overjoyed and finally found the memory problem! I guess it doesn’t hurt to read a lot of articles when you’re on the prowl

However, even if you know the memory is abnormal, you still can’t locate which code is causing…

Xiao Wang calmed down and continued to observe the rules. Finally, he found that every time he jumped from page A, the memory would increase several meters, and GC could not be recycled. It must be that there is something wrong with this page!

So Wang cursed and began to read the code of this page, hoping to find the culprit of the memory leak. Let me see which ** wrote the memory leak code

Wang read the code word by word: but there is no problem ah, is a common list page, or RecyclerView to achieve, no problem ah

You can use the Dump function to view a snapshot of the current memory. If you want to Dump a snapshot of the current memory, you can Dump a snapshot of the current memory

Boy, it was Bitmap that took up so much memory, so Wang remembered the interview treasure book again

In Android 2.3.3(API Level 10) and earlier versions, Bitmap objects and their corresponding pixel data are stored separately. Bitmap objects are stored in the virtual machine heap, while pixel data is stored in Native memory.

From Android 3.0(API Level 11) to Android 7.1(API Level 25), Bitmap objects and their pixel data are stored in the virtual machine heap.

Starting with Android 8.0(API Level 26), Bitmap objects are stored in the virtual machine heap, and the corresponding pixel data is stored in the Native heap.

The phone wang tested was Android 10, and the Bitmap data was stored in the Native heap, so it was almost certain that the Bitmap caused the memory leak. It’s a big step forward, but there’s no reason why.

Wang found that click on the object, you can see all instances of the reference chain, this can put Wang happy bad, and Wang also found a very suspicious reference chain

It is not Coil’s Memory Cache, but there is clearly a Cache, how can it leak, is it the open source library bug?

Wang opened the RealMemoryCache class with some trepidation

This is a memory cache based on the LRU implementation, which at first glance seems to be fine

There was no time to study it carefully, wang thought. First, to see if anyone in the open source community had given feedback on the problem, Wang filtered the issue that contained the keyword “memory leak”

Fix Memory leak if request is started on detached View.

It seemed that the problem had been fixed and a new version had been released, so Wang immediately upgraded the version and tested it again. Sure enough, there was no leak

So immediately submitted the code, excitedly to show off to the boss!!

Their roots

Looking back, Wang thought, as a “motivated” programmer, I have to see what caused the leak ah

I open PR again, and among the many changes, I finally find a real code change, and the rest are all test cases

Wang can not help feeling, crooked fruit benevolence is professional ah, changed two lines of code will write a pile of test cases

Wang finally found out the cause of the leak. It turns out that when the page is switched quickly, sometimes the page is destroyed and the image is loaded. At this time, Coil will save the View object and wait for the release of View detach. So it will never be freed, and the Bitmap will be held by the View, and we all know that bitmaps are heavy users of memory, so it will take up a lot of memory.

The solution is to determine if the View is already Detach, and if it is, release it to avoid leaks.

Finally Xiao Wang happily off work.