Android memory overflow problem analysis

Source: Internet
Author: User
Bytes. If there is something bad, let's leave a comment. Then we will continue to improve the memory leakage problem, which will be helpful to everyone. Haha I. Overview 1 II. Android (Java) common bad code that is prone to memory leakage 1 (1) query the database without closing the cursor 2 (2) when constructing the adapter, no cached convertview 3 (3) when a bitmap object is not in use, call recycle () to release memory 4 (4) Release object reference 4 (5) other 5 3. Memory monitoring tool ddms --> heap 5 4. Memory analysis tool MAT (memory analyzer tool) 7 (1) generation. hprof file 7 (2) use mat for import. hprof file 8 (iii) Use Mat's View tool to analyze memory 8 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. II. The Android (Java) code that is common to cause memory leakage Android is mainly used in embedded devices. embedded devices are subject to some well-known restrictions, usually there is no high configuration, especially the memory is relatively limited. If the code we wrote contains too many improper memory usage, 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 size allocated by Android to the application process is as follows:/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 the # same memory level as services. write/sys/module/lowmemorykiller/parameters/adj, 14, 15 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 application 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 when the database is queried. Description: The database is usually queried in the program, but it is often not closed after the cursor is used. 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 = getcontentresolver (). query (Uri ...); if (cursor. movetonext ()){......} corrected sample code: 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, the cached convertview is not used. Description: Take constructing the baseadapter of the listview as an example, in baseadapter, the following method is improved: public view getview (INT position, view convertview, viewgroup parent) to provide the view object required by each item to listview. 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. For details about how listview recycles the view object of list items, see Android. widget. abslistview. Java --> void addscrapview (view scrap. Sample Code: public view getview (INT position, view convertview, viewgroup parent) {view = new XXX (...);...... return view;} corrected sample code: public view getview (INT position, view convertview, viewgroup parent) {view = NULL; If (convertview! = NULL) {view = convertview; populate (view, getitem (position ));...} else {view = new XXX (...);...} return view;} (3) Call recycle () to release the memory when the bitmap object is not in use. Description: Sometimes we manually operate the bitmap object. If a bitmap object occupies more memory, when it is not in use, you can call bitmap. the recycle () method recycles the memory occupied by pixels of this object, but this is not necessary, depending on the situation. You can take a look at the comments in the Code:/*** free up the memory associated with this bitmap's pixels, and mark the * 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 free up this memory when * There are no more references to this bitmap. */(4) Reference description of the release object: this situation is difficult to describe. Here are two examples. Example A: assume that the following operations are performed on the 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 operations on 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 modified :...... 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 listen to the telephone service in the system in the lockscreen interface to obtain some information (such as signal strength ), 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 recycled by zookeeper. 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) The most typical release of resources in other android applications is 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 --> it is impossible for heap to completely avoid bad code, no matter how careful It Is, in this case, some tools are required to help us check whether there is any memory leakage in the code. 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 ). The steps for using heap to monitor the memory usage of application processes are as follows: 1. after eclipse is started, switch to the ddms perspective and confirm that the devices view and heap view are all open. 2. connect your phone to your computer through 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. 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 devices view. 6. click the "cause GC" button in the heap view. 7. in the heap view, the details of the memory usage of the selected process are 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 is refreshed on a regular basis, and the changes in memory usage can be seen during constant operations on applications. c) the parameters of memory usage information can be known by name, I will not go into details 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. It can be determined 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, it does not cause the object not to be garbage collected, so although we will continuously generate many objects, in the continuous GC process of virtual machines, these objects are recycled, and the memory usage will reach a stable level; c) otherwise, if the reference of the released object exists in the Code, the total size of the data object will not be significantly reduced after each GC, as the number of operations increases, the value of total size increases, and the process is killed until the maximum number 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. How does Android memory overflow occur? The android virtual machine is a register-based Dalvik. Its maximum heap size is generally 16 m, and some machines are 24 m. Therefore, the memory space we can use is limited. If our memory usage exceeds a certain level, an outofmemory error occurs. Why is memory insufficient? I think there are two main reasons: Due to program errors, some resources (such as context) can be referenced for a long time, causing memory leakage and resources cannot be released. Saves multiple objects (such as Bitmap) that consume too much memory, resulting in memory exceeding the limit. 3. The evil static is a keyword in Java. When it is used to modify a member variable, the variable belongs to the class, not the instance of the class. Therefore, the life cycle of a variable modified with static is very long. If you use it to reference some instances that consume too much resources (the case of context is the most), you should be cautious. Public class classname {Private Static Context mcontext; // omitting} is dangerous. If you assign an activity value to mcontext. Even if the activity has been ondestroy, the activity will not be released because there are still objects that store its reference. Let's take an example in the android document. Private Static drawable sbackground; @ override protected void oncreate (bundle state) {super. oncreate (State); textview label = new textview (this); label. settext ("leaks are bad"); If (sbackground = NULL) {sbackground = getdrawable (R. drawable. large_bitmap);} label. setbackgrounddrawable (sbackground); setcontentview (Label);} sbackground is a static variable, but we found that we did not explicitly Save the reference of contex. However, after drawable is connected to view Rawable sets the view as a callback. Because the view contains the reference of context, we still save the reference of context. The reference chain is as follows: drawable-> textview-> context. Therefore, the context is not released and Memory leakage occurs. How can we effectively avoid such a reference? First, we should try our best to avoid using static member variables to reference instances that consume too much resources, such as context. Second, use the application context whenever possible. Because the application context has a long life cycle, it will not cause memory leakage if referenced. Third, use weakreference instead of strong reference. For example, you can use weakreference <context> mcontextref. For details about this part, see the article in the android document. 4. It is a thread fault. The thread is also an important source of Memory leakage. The main cause of thread Memory leakage is the uncontrollable thread lifecycle. Let's consider the following code. Public class myactivity extends activity {@ override public void oncreate (bundle savedinstancestate) {super. oncreate (savedinstancestate); setcontentview (R. layout. main); New mythread (). start ();} private class mythread extends thread {@ override public void run () {super. run (); // do somthing} This code is very common and simple, and is often used. Let's think about a problem: assume that the run function of mythread is a very time-consuming operation. When we enable this thread, we change the horizontal screen of the device to a vertical screen, in general, the screen will re-create the activity when switching. According to our ideas, the old activity should be destroyed. However, in fact, this is not the case. Because our thread is an internal class of activity, a reference of activity is saved in mythread. When the run function of mythread is not completed, mythread will not be destroyed, therefore, the old activity referenced by it will not be destroyed, so Memory leakage occurs. Some people like to use asynctask provided by Android, but in fact asynctask is more serious. This kind of memory leakage problem occurs only when the run function does not end, however, the internal implementation mechanism of asynctask is to use threadpoolexcutor. the life cycle of the thread object generated by this class is uncertain and cannot be controlled by the application. Therefore, if asynctask is used as the internal class of the activity, it is more prone to memory leakage. How should we solve the memory leakage caused by such threads? First, change the internal class of the thread to the static internal class. Second, use weak references within the thread to save context references. The solution model is as follows: public abstract class weakasynctask <Params, progress, result, weaktarget> extends asynctask <Params, progress, result> {protected weakreference <weaktarget> mtarget; public weakasynctask (weaktarget target) {mtarget = new weakreference <weaktarget> (target) ;}/ ** {@ inheritdoc} */@ override protected final void onpreexecute () {final weaktarget target = mtarget. get (); If (target! = NULL) {This. onpreexecute (target) ;}}/** {@ inheritdoc} */@ override protected final result doinbackground (Params... params) {final weaktarget target = mtarget. get (); If (target! = NULL) {return this. doinbackground (target, Params);} else {return NULL ;}/ ** {@ inheritdoc} */@ override protected final void onpostexecute (result) {final weaktarget target = mtarget. get (); If (target! = NULL) {This. onpostexecute (target, result) ;}} protected void onpreexecute (weaktarget target) {// no default action} protected abstract result doinbackground (weaktarget Target target, Params... params); protected void onpostexecute (weaktarget target, result) {// no default action }}
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.