Android Best performance Practice (ii)--Analyze memory usage

Source: Internet
Author: User

Reprinted from: http://blog.csdn.net/guolin_blog/article/details/42238633

Since Android is an operating system developed for mobile devices, we should always take the memory issue into account when developing applications. Although the Android system has a garbage collection mechanism, this does not mean that we can completely ignore when to allocate or free memory. Even if we all follow the programming recommendations given in the previous article to write programs, there is a good chance of memory leaks or other types of memory problems. So the only way to solve the problem is to try to analyze the memory usage of the application, and this article will teach you how to analyze it. If you haven't read the previous article, it's recommended to read the best Android Performance Practice (a)--manage the memory properly .

Although the current cell phone memory is very large, but we all know that the system is not possible to allocate all the memory to our application. Yes, each program will have a memory limit that can be used, which is called the heap size. Different mobile phones, heap size is not the same, with the current hardware equipment is increasing, the heap size is already from Nexus One 32MB, the Nexus 5 o'clock 192MB. If you want to know what the heap size of your phone is, you can call the following code:

[Java]View Plaincopyprint?
    1. Activitymanager manager = (Activitymanager) getsystemservice (Context.activity_service);
    2. int heapsize = Manager.getmemoryclass ();
Activitymanager manager = (Activitymanager) getsystemservice (context.activity_service); int heapsize = Manager.getmemoryclass ();

The result is returned in megabytes, where the memory used to develop the application does not exceed this limit, or outofmemoryerror will occur. Therefore, for example, in our program we need to cache some data, we can determine the capacity of the cache data according to the heap size.

Let's talk about the GC operation of Android, the GC full name is Garbage Collection, which is called garbage collection. The Android system triggers GC operations at the right time, and once the GC is in place, some objects that are no longer used are recycled. So what objects are considered to be unused and can be recycled? Let's take a look at the following picture:

Each blue circle represents an object in memory, and the arrows between the circles are their referential relationships. Some of these objects are active, and some are no longer being used. Then the GC operation starts with an object called roots, and all the objects it can access indicate that it is still in use and should be preserved, while the other objects indicate that they are no longer being used, as shown in:

As you can see, all the yellow objects are still retained by the system, and the blue objects are collected by the system in the GC operation, which is probably the simple GC process of the Android system.

So when does it trigger a GC operation? This is usually determined by the system, we generally do not need to proactively notify the system should go to the GC (although we can do this, as described below), but we can still listen to the system's GC process, in order to analyze our application's current memory state. So how do you listen to the system's GC process? In fact, it is very simple, every time a GC operation, the system will print a log in Logcat, we just have to analyze this log, the basic format of the log is as follows:

[Plain]View Plaincopyprint?
    1. D/DALVIKVM: <GC_Reason> <amount_freed>,
D/DALVIKVM: <GC_Reason> <amount_freed>, 

Note that I am still using the Dalvik virtual machine to illustrate that the content printed in art is basically similar.

First part Gc_reason, this is the reason for triggering this GC operation, generally there are the following several reasons to trigger the GC operation:

    • gc_concurrent: When the heap memory of our application is nearly full, the system automatically triggers a GC operation to free up memory.
    • Gc_for_malloc: When our application needs to allocate more memory, but the existing memory is insufficient, the system will perform a GC operation to free up memory.
    • gc_hprof_dump_heap: When generating the HPROF file, the system will perform GC operations, about the HPROF file we will talk about below.
    • gc_explicit: This is what we have just mentioned, the proactive notification system to perform GC operations, such as calling the System.GC () method to notify the system. Or in Ddms, a tool button can also be used to explicitly tell the system to perform GC operations.

The second part, amount_freed, indicates how much memory the system freed up through this GC operation.

The heap_stats then displays the idle scale of the current memory and usage (the active object occupies memory/current program total memory).

The last pause_time indicates when the GC operation caused the application to pause. On this pause, Android has been optimized in version 2.3, before 2.3 GC operation is not concurrent, that is, the system is in the GC, then the application can only block waiting for GC end. Although the blocking process is not very long, that is, hundreds of milliseconds, the user may feel a slight lag when using our program. Since 2.3, the GC operation has been changed in a concurrent manner, that is, the GC process does not affect the normal operation of the application, but at the beginning and end of the GC operation will be briefly blocked for a period of time, but the optimization to this extent, the user is completely undetectable.

The following is a log that the GC operation prints in Logcat:

As you can see, the format described above is exactly the same, with the last pause time 31ms+7ms, the time at which the GC starts, and the time at the end of the pause. In addition, according to the process ID to distinguish which program is the GC operation, then you can see that this GC log is 24699 of this program.

So this is the GC log that is printed when using the Dalvik runtime environment, and since Android 4.4 has been added to the art runtime environment, printing GC logs in art is basically the same as Dalvik, as shown in:

Believe there is no hard to understand the place, art is only the content of the format has slightly changed, the main content of the printing is still unchanged.

Well, through the log we can simply understand the system's GC work, but if we want to know more clearly in real-time memory usage of the current application, only through the log is a bit out of the way, we need to use the tools provided in DDMS to achieve.

Open the Ddms interface, select the application process you want to observe in the left panel, then click the Update heap button, then click the Heap tab in the right panel, then click the Cause GC button to observe the application memory usage in real time. As shown in the following:

Then continue to operate our application, then continue to click on the cause GC button, if you find that repeated operation of a feature will cause the application memory to continue to increase without falling, then it is very likely that there is a memory leak.

Okay, we're done talking about GC, so let's talk about memory leaks in Android. What you need to know is that the garbage collection mechanism in Android does not prevent a memory leak, and the main reason for the memory leak is that some of the objects that are being held by others should be referenced by some other object that should be recycled, causing the garbage collector to fail to reclaim those objects, and there will be a memory leak. For example, a system component like activity, which contains many controls and even pictures, is a serious memory leak if it cannot be reclaimed by the garbage collector.

Let's simulate a scenario in which an activity memory leak occurs, and the inner class is believed to be useful, and if we define a non-static inner class in a class, the inner class holds a reference to the outer class, as follows:

[Java]View Plaincopyprint?
  1. Public class Mainactivity extends Actionbaractivity {
  2. @Override
  3. protected void OnCreate (Bundle savedinstancestate) {
  4. super.oncreate (savedinstancestate);
  5. Setcontentview (R.layout.activity_main);
  6. Leakclass Leakclass = new Leakclass ();
  7. }
  8. class Leakclass {
  9. }
  10. ......
  11. }
public class Mainactivity extends Actionbaractivity {    @Override    protected void OnCreate (Bundle Savedinstancestate) {        super.oncreate (savedinstancestate);        Setcontentview (r.layout.activity_main);        Leakclass Leakclass = new Leakclass ();    }    Class Leakclass {    }    ...}

At this point, the code is fine, because although leakclass this inner class holds mainactivity references, it does not prevent mainactivity from being reclaimed by the garbage collector as long as it does not survive longer than mainactivity. So now let's make the following modifications to the code:

[Java]View Plaincopyprint?
  1. Public class Mainactivity extends Actionbaractivity {
  2. @Override
  3. protected void OnCreate (Bundle savedinstancestate) {
  4. super.oncreate (savedinstancestate);
  5. Setcontentview (R.layout.activity_main);
  6. Leakclass Leakclass = new Leakclass ();
  7. Leakclass.start ();
  8. }
  9. class Leakclass extends Thread {
  10. @Override
  11. public Void Run () {
  12. While (true) {
  13. try {
  14. Thread.Sleep (* 1000);
  15. } catch (Interruptedexception e) {
  16. E.printstacktrace ();
  17. }
  18. }
  19. }
  20. }
  21. ......
  22. }
public class Mainactivity extends Actionbaractivity {    @Override    protected void OnCreate (Bundle Savedinstancestate) {        super.oncreate (savedinstancestate);        Setcontentview (r.layout.activity_main);        Leakclass Leakclass = new Leakclass ();        Leakclass.start ();    }    Class Leakclass extends Thread {        @Override public        void Run () {while            (true) {                try {                    Thread.Sleep ( (* *);                } catch (Interruptedexception e) {                    e.printstacktrace ();    }}}} ......}

This is a bit different, we let leakclass inherit from thread, and rewrite the Run () method, and then start Leakclass this thread in the OnCreate () method of mainactivity. The Leakclass run () method runs a dead loop, which means that the thread will never execute the end, then the Leakclass object will not be released, and the mainactivity it holds will not be released, then the memory leak occurs.

Now we can run the program, and then constantly rotate the phone to allow the program to switch between the horizontal screen and the vertical screen, because each switch activity will go through a re-creation process, and the previously created activity can not be recycled, In the long-time operation our application will occupy more and more memory, eventually outofmemoryerror.

Below I post a picture of the GC log printing that constantly switches between the two screens as follows:

As you can see, the memory occupied by the application is rising. The most frightening thing is that once the memory is up, it will never come down again until the program crashes, because this part of the leaked memory has never been reclaimed by the garbage collector.

With the GC logs and the DDMS tools learned above, it is now easier to see if there is a memory leak in the application. But if there is a memory leak, how should we locate the specific problem? This requires the use of a memory analysis tool called Eclipse Memory Analyzer (MAT). We need to download this tool first, yes: http://eclipse.org/mat/downloads.php. This tool is divided into Eclipse plug-in and standalone version, if you are using Eclipse development, then you can use the plug-in version of the mat, very convenient. If you're using Android Studio, you'll only be able to use the stand-alone version of Mat.

After downloading, we begin to learn how to analyze the causes of memory leaks, first of all go to the Ddms interface, then select the application process we want to observe on the left panel, then click the Dump HPROF file button, as shown in:

Clicking on this button will require a period of time before it generates a hprof file that records all the data inside our application. But the mat is still unable to open this file, we also need to convert the Hprof file from the Dalvik format to J2SE format, using the Hprof-conv command to complete the conversion work, as follows:

[Plain]View Plaincopyprint?
    1. Hprof-conv dump.hprof Converted-dump.hprof
Hprof-conv dump.hprof Converted-dump.hprof

The hprof-conv command file is stored under the <android sdk>/platform-tools directory. In addition, if you are using the plug-in version of the mat, you can also open the generated hprof file directly in Eclipse, without having to convert this step into a format.

OK, so then we can try to use the Mat tool to analyze the reason for the memory leak, and here's to remind you that Mat doesn't tell us exactly where a memory leak happened, but instead provides a whole bunch of data and clues, We need to analyze the data ourselves to determine if there is a real memory leak. Then run the Mat tool now and choose to open the converted Converted-dump.hprof file as shown in:

There are a lot of features in the mat, so we just have to learn a few of the most common ones. The most central pie chart shows the ratio of the largest number of objects to the amount of memory that is provided in this graph, and we can ignore it. There are a few very useful tools at the bottom of this pie chart, so let's take a look at it.

histogram can list the name, number, and size of each object in memory.

Dominator Tree sorts all in-memory objects by size, and we can parse the reference structure between objects.

Generally the most commonly used is the above two functions, then we start from Dominator Tree began to learn.

Now click on Dominator Tree and the results are as follows:

This picture contains a lot of information, I come with you to analyze. First the retained heap represents the total memory of this object and other references it holds (both direct and indirect), so the first two rows of the retained heap are the largest, and when we analyze memory leaks, the largest memory object is also the most suspect.

In addition, you should be able to notice that there is a file-type icon on the leftmost side of each line, some of which have a red dot in the lower left corner, or none. Objects with red dots indicate that they can be accessed by GC roots, and the objects that can be accessed by GC Root cannot be recycled, as explained above. So does this mean that all red objects are leaking objects? Of course not, because some object systems need to be used all the time and should not be recycled. We can notice that all of the objects with the red dots have a system Class on the far right, indicating that this is a managed object, not an object created by ourselves and causing a memory leak.

Can't you see the reason for the memory leak? It is true that memory leaks are not so easily identified, and we need to analyze them further. In addition to the line with the system class, the largest is the second row of the Bitmap object, although the bitmap object can not now be accessed by the GC roots, but does not mean that bitmap hold other references will not be accessed by GC roots. Now we can go to the second row right-click Path to GC Roots-exclude weak references, why choose Exclude weak references? Because a weak reference does not prevent the object from being reclaimed by the garbage collector, we exclude it directly here, as shown in the following example:

As you can see, after the bitmap object has been referenced in layers, the object is Mainactivity$leakclass, then there is a red icon in the lower left corner of the icon, which means that it can be accessed by the GC roots, and this is the thread that we created ourselves. is not a system class, then because Mainactivity$leakclass can be accessed by GC roots to cause it cannot be recycled, other references it holds cannot be recycled, including mainactivity, Also includes images included in the mainactivity.

In this way, we succeeded in finding out the cause of the memory leak. This is a common analysis in Dominator tree, that is, the search for large memory objects to the path of GC roots, because the higher the memory consumption of the object is more questionable.

Next we will learn the usage of histogram, go back to the overview interface, click Histogram, the results as shown:

Here is the name, number and size of all the objects in the current application are listed, it should be noted that the object here is only shallow heap and no retained heap, then what does shallow heap mean? Is the size of the current object's own memory, does not include the reference relationship, for example, byte[] object Shallow heap is the highest, indicating that we use a lot of byte[] type of data, such as pictures. You can see who is using these byte[] by right-click List objects, with incoming references.

So how to analyze the causes of memory leaks through histogram? Of course, you can also use and Dominator tree in a similar way, that is, the analysis of large memory objects, such as byte[] object memory consumption is very high, we through the analysis of byte[], and finally can find the memory leaks, But here I'm going to use another way that's better for histogram. As you can see, the number of objects can be displayed in histogram, so for example, we now suspect that there may be a memory leak in mainactivity, you can search for "mainactivity" in the Regular expression box in the first row, as shown below:

As you can see, all the objects containing the word "mainactivity" are listed here, with the first line being an instance of mainactivity. However, it has not been noted that there are 11 instances of mainactivity in memory, which is not normal, in case an activity should have only one instance. In fact, these objects are because we have just kept on the screen switching between the production, because the screen switch once, the activity will go through a re-creation process, but because of the existence of Leakclass, the previous activity can not be recovered by the system, Then there is a case where there are multiple instances of this activity.

Next to the mainactivity right-click List objects, with incoming references see the specific mainactivity instance, as shown in:

If you want to see the specific cause of a memory leak, you can right-click the Path to GC Roots-exclude weak references for any one of the mainactivity instances, as shown in the following:

As you can see, we have again found the cause of the memory leak because of the Mainactivity$leakclass object.

Well, this is probably the most common use of the mat tools, of course, here also to remind you that the tool is dead, people are alive, mat there is no way to ensure that the cause of the memory leak can be found out, or need us to the code of the program have enough knowledge, know which objects are alive, And the reasons for their survival, and then combined with the data of mat to carry out specific analysis, it is possible to put some deep hidden problems to find out the cause.

So today is also introduced a lot of content, the explanation of this article to here, because the Spring Festival is about to come, this is the last article this year, here first to worship an early, I wish everyone happy Spring Festival. During the holiday hope that everyone can be like me, put down the code, a good rest for a while, so the next article will be updated in the year after the introduction of some high-performance coding skills, interested friends please continue to read Android Best performance Practice (iii)-high-performance coding optimization .

Android Best performance Practice (ii)--Analyze memory usage

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.