Android Memory leakage debugging

Source: Internet
Author: User

I. Overview

Java programming is often overlooked, but a very important issue is memory usage. Android applications are mainly written in Java, so this problem also occurs in Android development. This article does not discuss Java programming, but sorts out such problems in Android, especially in application development.

Since the author has not been familiar with Android for a long time, please correct me if you have misstated it.
2. Common bad code in Android (Java) that is prone to memory leakage

Android is mainly used in embedded devices. embedded devices generally do not have high configurations due to some well-known restrictions, especially limited memory. If there are too many improper memory usage items in the code we write, it will inevitably make our devices run slowly or even crash. To ensure secure and fast running of Android applications, each android application uses a proprietary Dalvik Virtual Machine instance to run. It is incubated by the zygote service process, that is to say, each application runs in its own process. On the one hand, if the program encounters a memory leak during the running process, it will only kill its own process without affecting other processes (if it is a system process such as system_process, will cause the system to restart ). On the other hand, Android allocates different memory usage ceilings for different types of processes. If the memory used by the application process exceeds the upper limit, the system will consider the memory leakage and kill it. The maximum memory allocated by Android to application processes is as follows:

Location:/android_source/system/CORE/rootdir/init. RC Script

# Define the oom_adj values for the classes of processes that can be

# Killed by the kernel. These are used in activitymanagerservice.

Setprop Ro. foreground_app_adj 0

Setprop Ro. visible_app_adj 1

Setprop Ro. secondary_server_adj 2

Setprop Ro. backup_app_adj 2

Setprop Ro. home_app_adj 4

Setprop Ro. hidden_app_min_adj 7

Setprop Ro. content_provider_adj 14

Setprop Ro. empty_app_adj 15

# Define the memory thresholds at which the above process classes will

# Be killed. These numbers are in pages (4 K ).

Setprop Ro. foreground_app_mem 1536

Setprop Ro. visible_app_mem 2048

Setprop Ro. secondary_server_mem 4096

Setprop Ro. backup_app_mem 4096

Setprop Ro. home_app_mem 4096

Setprop Ro. hidden_app_mem 5120

Setprop Ro. content_provider_mem 5632

Setprop Ro. empty_app_mem 6144

# Write value must be consistent with the above properties.

# Note that the driver only supports 6 slots, so we have home_app at

# Same memory level as services.

Write/sys/module/lowmemorykiller/parameters/adj

Write/proc/sys/Vm/overcommit_memory 1

Write/proc/sys/Vm/min_free_order_shift 4

Write/sys/module/lowmemorykiller/parameters/minfree 1536,2048, 4096,5120, 5632,6144

# Set init its forked children's oom_adj.

Write/proc/1/oom_adj-16

Because our applications can use limited memory, we need to pay special attention to memory usage when writing code. The following are some common cases of improper memory usage.

(1) The cursor is not closed during database query.

Description:

The program usually queries the database, but it often does not close after using the cursor. If our query result set is small, memory consumption is not easy to find. Memory problems can be reproduced only when a large number of operations are performed at a regular time, this will cause difficulties and risks for future testing and troubleshooting.

Sample Code:

Cursor cursor = getcontentresolver (). Query (Uri ...);

If (cursor. movetonext ()){

......

}

Corrected sample code:

Cursor cursor = NULL;

Try {

Cursor = getcontentresolver (). Query (Uri ...);

If (cursor! = NULL & cursor. movetonext ()){

......

}

} Finally {

If (cursor! = NULL ){

Try {

Cursor. Close ();

} Catch (exception e ){

// Ignore this

}

}

}

(2) When constructing an adapter, no cached convertview is used

Description:

Taking constructing the baseadapter of listview as an example, the method is improved in baseadapter:

Public View getview (INT position, view convertview, viewgroup parent)

To provide listview with the view object required by each item. Initially, the listview will instantiate a certain number of view objects from the baseadapter based on the current screen layout, and the listview will cache these view objects. When you scroll up the listview, the view object originally located in the top list item will be recycled and then used to construct the bottom list item that appears. This construction process is completed by the getview () method, getview () the second view convertview parameter is the view object of the cached list item. (convertview is null if no view object is cached during initialization ).

From this we can see that if we don't use convertview, but re-instantiate a view object in getview () every time, it will be a waste of resources and time, which will also increase the memory usage. You can view the process when listview recycles the view object of list item:

Android. widget. abslistview. Java --> void addscrapview (view scrap) method.

Sample Code:

Public View getview (INT position, view convertview, viewgroup parent ){

View view = new XXX (...);

......

Return view;

}

Corrected sample code:

Public View getview (INT position, view convertview, viewgroup parent ){

View view = NULL;

If (convertview! = NULL ){

View = convertview;

Populate (view, getitem (position ));

...

} Else {

View = new XXX (...);

...

}

Return view;

}

(3) Call recycle () to release memory when the bitmap object is not in use

Description:

Sometimes we will manually operate bitmap objects. If a bitmap object occupies memory, when it is not in use, we can call bitmap. the recycle () method recycles the memory occupied by pixels of this object, but this is not necessary, depending on the situation. Let's take a look at the comments in the Code:

/**

* Free up the memory associated with this bitmap's pixels, and mark

* Bitmap as "dead", meaning it will throw an exception if getpixels () or

* Setpixels () is called, and will draw nothing. This operation cannot be

* Reversed, so it shoshould only be called if you are sure there are no

* Further uses for the bitmap. This is an advanced call, and normally need

* Not be called, since the normal GC process will be free up this memory when

* There are no more references to this bitmap.

*/
(4) Release Object Reference

Description:

This situation is difficult to describe. Two examples are provided.

Example:

Assume that the following operations are performed:

Public class demoactivity extends activity {

......

Private handler mhandler =...

Private object OBJ;

Public void operation (){

OBJ = initobj ();

...

[Mark]

Mhandler. Post (New runnable (){

Public void run (){

Useobj (OBJ );

}

});

}

}

We have a member variable obj. in operation (), we want to post the operation for processing the OBJ instance to the messagequeue of a thread. In the above Code, even if the thread where mhandler is located uses the object referenced by OBJ, this object will not be reclaimed because demoactivity. OBJ still has reference to this object. So if this object is no longer used in demoactivity, you can release the object reference at the [Mark] position, and the code can be changed:

......

Public void operation (){

OBJ = initobj ();

...

Final object o = OBJ;

OBJ = NULL;

Mhandler. Post (New runnable (){

Public void run (){

Useobj (O );

}

}

}

......

Example B:

Suppose we want to use the *** telephone service in the system to obtain some information (such as signal strength) on the lockscreen interface ), you can define a phonestatelistener object in lockscreen and register it in the telephonymanager service. For lockscreen objects, a lockscreen object is created when the screen lock interface needs to be displayed. When the screen lock interface disappears, the lockscreen object is released.

However, if you forget to cancel the previously registered phonestatelistener object when releasing the lockscreen object, lockscreen cannot be reclaimed. If the screen lock interface is constantly displayed and disappears, a large number of lockscreen objects cannot be recycled, causing outofmemory and causing the system_process process to crash.

In short, when an object a with a short life cycle is referenced by an object B with a long life cycle, at the end of a's life cycle, the references to a should be removed from B.
(5) Others

The typical release of resources in Android applications is in onpause (), onstop (), and ondestroy () during the activity lifecycle () method. This is a basic situation and is not described in detail here. For details, refer to the introduction to the activity lifecycle in the official documentation to determine when resources should be released.
Iii. Memory monitoring tool ddms --> heap

No matter how careful you are, it is impossible to completely avoid bad code. At this time, some tools are required to help us check whether there is any place in the code that will cause memory leakage. The ddms in Android tools comes with a very good memory monitoring tool heap (here I use the ADT plug-in of eclipse, and take the real machine as an example, the situation in the simulator is similar ). To monitor the memory usage of an application process using heap, follow these steps:

1. After eclipse is started, switch to the ddms *** graph and confirm that the devices view and heap view are all open;

2. Connect your phone to your computer via USB. Make sure that the phone is in "USB debugging" mode instead of "Mass Storage ";

3. After the connection is successful, the device serial number and running process information are displayed in the devices view of ddms;

4. Click the process you want to monitor, such as the system_process process;

5. Click the "Update Heap" icon in the top row of the selected devices View Interface;

6. Click "cause GC" in the heap view;

7. In the heap view, the memory usage of the selected process is displayed [].

Note:

A) clicking the "cause GC" button is equivalent to requesting a GC operation from the VM;

B) when the memory usage information is displayed for the first time, you do not need to constantly click "cause GC". The heap view interface will be refreshed on a regular basis, the changes in memory usage can be seen during the continuous operation of applications;

C) the parameters of the memory usage information can be known Based on the name and will not be described here.

How can we know whether our program has the possibility of Memory leakage. Here, you need to pay attention to a value: In the heap view, there is a type called data object, that is, the data object, that is, a large number of class type objects in our program. In a row of data object, there is a column named "total size", whose value is the total memory of all Java Data Objects in the current process. Generally, the size of this value determines whether memory leakage exists. You can judge this as follows:

A) constantly operate on the current application, and observe the total size value of the data object;

B) under normal circumstances, the total size value will be stable within a limited range. That is to say, because the code in the program is good, the object will not be garbage collected, therefore, although we continuously generate many objects during operations, these objects are recycled during the continuous GC of virtual machines, memory usage will reach a stable level;

C) if the Code does not release the object reference, the total size value of the data object will not be significantly reduced after each GC, as the number of operations increases, the value of total size increases,

The process is killed until the upper limit is reached.

D) The system_process process is used as an example. In my testing environment, the total size of the Data Object occupied by the system_process process will normally be 2.2 ~ 2.8, and when the value exceeds 3.55, the process will be killed.

In short, using the heap View tool of ddms can easily confirm whether our program has the possibility of Memory leakage.
4. Memory Analysis Tool (memory analyzer tool)

If ddms does discover Memory leakage in our program, how can we locate the specific problematic code snippet and find the problem? If you analyze the code logic from start to end, it will drive people crazy, especially when maintaining the code written by others. Here is an excellent memory analysis tool-memory analyzer tool (MAT ).

MAT is an Eclipse plug-in with a separate RCP client. For more information, see www.eclipse.org/mat. In addition, there are complete tutorials in the help documentation after mat installation. Here, we will only illustrate how to use it. I use the mat Eclipse plug-in, which is easier to use than RCP.

Several steps are required to use mat for memory analysis, including generating the. hprof file, opening the mat and importing the. hprof file, and using the mat View tool to analyze the memory. The following is a detailed description.
(1) generate the. hprof File

Generate. there are many methods for hprof files, and they are generated in different Android versions. the hprof method is slightly different. I use version 2.1, which is generated in each version. for the prof file method, see:

Http://android.git.kernel.org /? P = platform/Dalvik. Git; A = blob_plain; F = docs/heap-profiling.html; HB = head.

1. Open eclipse and switch to the ddms *** graph. Check that the devices, heap, and logcat views are enabled;

2. Link your phone to your computer and make sure that you use the "USB debug" mode instead of the "Mass Storage" mode;

3. After the connection is successful, the device serial number and some processes running on the device are displayed in the devices view;

4. Click the process of the application to be analyzed, and select the update heap and dump hprof file buttons in the icon button above the devices view;

5. this is where the ddms tool will automatically generate the currently selected process. hprof file, convert it, and store it in sdcard. If you have installed the mat plug-in, the mat will be automatically enabled and started. hprof file for analysis;

Note: Steps 4th and 5th can be used normally only when sdcard is available and the current process has the write permission (write_external_storage) to the sdcard. Otherwise. the hprof file will not be generated and will be displayed in logcat, such

Error/dalvikvm (8574): hprof: Can't open/sdcard/COM. XXX. hprof-hptemp: Permission denied.

.

If we do not have sdcard, or the current process does not have the permission to write data to sdcard (such as system_process), we can do this:

6. In the current program, for example, some code in the framework, you can use:

Public static void dumphprofdata (string filename) throws ioexception

Method to manually specify the location where the. hprof file is generated. For example:

Xxxbutton. setonclicklistener (New View. onclicklistener (){

Public void onclick (view ){

Android. OS. Debug. dumphprofdata ("/data/temp/MyApp. hprof ");

......

}

}

The above code is intended to capture memory usage information when xxxbutton is clicked and save it at our specified location:/data/temp/MyApp. hprof, so there is no permission restriction, and you do not need to use sdcard. Make sure that the/data/TEMP directory exists. This path can be defined by yourself, and can also be written as a path in sdcard.

(2) Use mat to import the. hprof File

1. If the. hprof file is automatically generated by ECLIPSE, you can use the mat plug-in to open it directly (it may be supported by a newer ADT );

2. if. the hprof file cannot be directly opened by mat, or android is used. OS. debug. manually generated by the dumphprofdata () method. hprof file, you need. to convert the hprof file, use the following method:

For example. copy the hprof file to the/android_sdk/tools directory on the PC, and enter the hprof-Conv XXX command. hprof yyy. hprof, where xxx. hprof is the original file, YYY. hprof is the converted file. The converted files are automatically stored in the/android_sdk/tools directory. OK. Till now, the. hprof file has been processed and can be used to analyze Memory leakage.

3. In eclipse, choose windows> open perspective> Other> memory analyzer, or press RCP of memory analyzer tool. In the mat, click File-> open file to browse and import the. hprof file just converted.
(3) Use Mat's View tool to analyze memory

Import. after the hprof file is created, the mat automatically parses and generates a report. Click dominator tree, group by package, and right-click the package class you have defined, select List objects-> with incoming references in the pop-up menu. All the suspicious classes are listed. Right-click an item and choose path to GC roots-> exclude weak/soft references, all classes related to the program with Memory leakage will be further filtered out. Based on this, we can track a class in the code that produces leakage.

Shows the mat interface.

The specific analysis method is not described here, because the help documents on the official website and client of Mat are very detailed.

It is important to understand the role of various views in mat, for example, introduced in www.eclipse.org/mat/about/screenshots.php.

In short, the fundamental idea of using mat to analyze the memory to find Memory leakage is to find out which class of object reference is not released, and find the reason why it is not released, in this way, you can easily locate the logic of the segments in the code.

So far, please do it yourself!

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.