Hello everyone! I am about to graduate students, in their spare time often see the great God wrote blog learned a lot of things. Recently in the graduation design encountered some problems, and then put their own problems and solutions to summarize, there is no place to hope that you have a lot to forgive, put forward criticism and guidance.
This blog post mainly describes the use of Androidstudio memory for analysis and tracking, as well as from the source point of view to solve the imageloader caused by the oom problem.
I am doing the project using the Imageloader to load the picture, I am also the first time to use, I took it directly. After writing the code to run a very normal loading picture, and did not find anything wrong. But the problem was found in the test. When you open the software multiple times to browse the big picture activity (each time the picture is different), then in this activity click Back, the screen will suddenly turn black, and then back to the mainactivity, and did not go back to the first level of activity, Even multiple activity that was opened between them did not return. Thinking about the question, the suspicion might be restarting the app. But the large picture of the activity began to open a few times can be normal back to the first level of activity, and more open several times can not return to normal, this time I began to see the logcat out of the log, to see if there is anything unusual. found that Imageloader produced an oom bug. Such as:
and then on the Internet to check the imageloader caused by memory leaks, found that a lot of people met, but when it comes to solving the solution, and there is no good answer. Most of these are the configuration issues in Imageloaderconfiguration.builder (context) and Displayimageoptions.builder (), but they do not solve the problem. Others say a picture loading frame, like Universal-image-loader (UIL) and Google's volley framework, I tried to change Universal-image-loader (UIL) This, but found that there is still this problem. And the project change a framework changes relatively large, there is no attempt to volley framework. Others say that it should be caused by the use of both cacheinmemory (true) and Cacheondisc (true), but I set them to false or cause oom, so I use my tools to analyze them.
Now that we have oom, we need to analyze the memory to see what the cause is. Using the Android Studio tool (found to be much more powerful than eclipse), there was a problem when observing with Androidstudio's memory tool, when I opened the activity several times, The memory has been growing, and the memory has not declined after each activity exit.
So when I've been browsing a lot of different pictures, After opening the activity several times, the memory has been growing, and when it grows to 120+m, the application suddenly hangs up and then restarts automatically. Having discovered this phenomenon, we can use the powerful tools of Androidstudio to analyze the cause of this problem. There are four buttons on the left side of the memory window, respectively:
Enabled (blue switch): is a normal switch function
Initiate GC (orange pickup): Just call the GC manually, we must manually click the Initiate GC button to manually trigger the GC before grasping the memory. This captured memory usage is not included in the Unreachable object (unreachable refers to objects that can be reclaimed by the garbage collector, but because no GC occurs, so there is no release, then the memory used in the capture of unreachable is these objects)
Dump Java Heap (purple with downward arrow): Gets the Hprof file (the Hprof file is the file we use when we use the Mat tool to analyze memory), but the file mat directly generated here is not directly available and needs to be converted into a standard hprof file. You can use the Androidstudio conversion or the Hprof-conv command to convert, online can be found.
Start Allocation Tracking (purple circled): Start distribution Tracking, first click to specify where to start tracking memory, and the second click to end the trace. So we intercept a section of memory to analyze, wait a few seconds Androidstudio will open a allocation view (like the Mat tool, but the mat tool is more powerful, we can also get the Hprof file, using mat to analyze) For example:
I intercepted this memory, and then we looked at the allocation view to analyze it.
Through the contents of the view we first see the Line 1 line Process It occupies 92 of the memory, then we will open it to see, each time only to open the memory of which the most occupied.
to the location of the red line can be, here has been to the Android graphics source level, so we do not need to look down. Let's take a look at the Imageloader on the red Line. Decodestream method:
vchlrglzcgxheujpdg1hcfrhc2vv4rj2wodw0kosxmfdtm7sw8fu2b34you1vdxiupba4nbqv7s3os/ Wwcvsu7j2vqrpsqo6pc9wpg0kpha+pgltzybhbhq9 "Displaybitmaptask" src= "/uploadfile/collfiles/20160506/ 20160506090822426.png "title=" \ "/>
The object is passed to the Displaybitmaptask member variable, and the Displaybitmaptask itself implements the Runnable interface. So I'm just wondering if it's displaybitmaptask that this class does not recycle the bitmap member variables that are causing the memory, so I'm going to let bitmap = null after the run () method runs out. It then ran the program again, but found that it did not solve the problem at all. This time again to think about the whole process, found that my operation is not right, although I successfully set the Displaybitmaptask in the bitmap member variable to empty, but he is only a real bitmap memory of a reference, I did not put the real bitmap memory space released, Just released one of his references. Through the online query found that bitmap will be stored in the C layer of memory, if we want to release his memory in the C layer, you can call the bitmap recycle () method, from the code, the method itself will invoke Bitmap.cpp in the Bitmap_recycle method, This is the native method. This tells the underlying to release the bitmap memory in layer C, and also set some related reference counts to 0. But it will not be released immediately, it depends on the system. A perfect solution at a sudden. Now that I have found the reason, it is good to do, I will bitmap = null This sentence changed to Bitmap.recycle (). OK, then I run again, found that the application directly on the collapse, as long as the logcat can catch log, all problems are resolved. Look at the log and find the following error:
By literal comprehension, our view shows the bitmap that has been recycle. Think about it. Indeed, we freed the bitmap directly from the Run method of a thread in Imageloader, so our application would not directly display an empty bitmap, which would of course cause errors. Since we cannot release the bitmap here, where should we release it? That must be called when our view is no longer using this bitmap, think about it, so we just have to release it in the activity or fragment ondestory () method? But then another problem arises, how do we get the bitmap object for this view in the upper application? Think of a half-day discovery seems to be only by rewriting the source of Imageloader to find ways to transfer this object to the upper application. Just as I was looking for a way to write this callback in Imageloader, I suddenly saw this code:
found that in fact the source of Imageloader has written for us this callback listener interface, and in the Imageloader DisplayImage method, also overloaded with a delivery Imageloaderlistener implementation of the object method. So we just need to implement imageloaderlistener this interface, and implement his Onloadingcomplete method, in this method to do the bitmap to do it.
We just need to call the Cleanbitmaplist () method again in the activity or fragment Ondestory () method. With the above changes I ran the app again and found that it really solved the problem, and my app's memory was no longer going up, but it went up and down.
Note: This method is better suited for cacheinmemory (false) and Cacheondisc (false) cases, and should be if you set these two to true, then the next time you load the picture, he will load the image from memory and hard disk, These two places also hold bitmap references, and the trying to use a recycled bitmap this error again. Of course you can also set to true, as long as the clear bitmap (which is where we call cleanbitmaplist) plus Mimageloader.cleardisccache () and Mimageloader.clearmemorycache () These two words can be.
Well, the whole imageloader caused by the oom problem of the analysis and resolution of the process is these, I hope that the need to help people, through this problem I also learned that the best solution to the problem is that we have to from the most fundamental source of the angle of analysis, so that can learn a lot of things, And can solve difficult problems
。