Many people think that Java programs, because there is a garbage collection mechanism, there should be no memory leaks. In fact, if we no longer use an object in a program, but because there is still a reference to it, the garbage collector cannot reclaim it, and of course the memory used by the object cannot be consumed, which results in a memory leak. If our Java is running for a long time, and this memory leak is constantly occurring, then no memory is available. Java, of course, is not the same as the memory leaks and C + +. If the Java program is completely finished, all its objects are unreachable, and the system can recycle them, and its memory leaks are limited to itself, without affecting the entire system. C + + memory leaks are worse, its memory leaks are system-level, even if the C + + program exits, its leaked memory can not be reclaimed by the system, never available, unless the machine is restarted.
An Android application's memory leak has little impact on other applications. To enable Android apps to run safely and quickly, each Android application uses a proprietary Dalvik virtual machine instance that is hatched by the zygote service process, which means that each application runs in its own process. Android allocates different memory usage caps for different types of processes, and if a memory leak occurs during a program that causes the application process to use more memory than the upper limit, it will be considered a memory leak by the system and killed, which causes only its own process to be killed. It does not affect other processes (which can cause a system restart if the system processes problems such as system_process).
One, the reference does not release caused by the memory leak
1.1 Memory leaks due to registration not canceled
This kind of Android memory leak is more serious than pure Java memory leak, because some other Android programs may reference our Anroid program objects (such as the registration mechanism). Even though our Android program is over, other reference programs still have a reference to an object in our Android program, and the leaked memory is still not garbage collected.
For example 1:
Suppose we want to listen to the phone service in the system in the lock screen (lockscreen) to get some information (such as signal strength, etc.), you can define a Phonestatelistener object in the Lockscreen. Register it with the Telephonymanager service at the same time. For Lockscreen objects, a Lockscreen object is created when the lock screen needs to be displayed, and the Lockscreen object is released when the lock screen disappears.
However, if you forget to cancel the Phonestatelistener object that we previously registered when releasing the Lockscreen object, it will cause lockscreen to be garbage collected. If the lock screen interface is constantly displayed and disappears, it will eventually cause outofmemory due to the fact that a large number of Lockscreen objects have no way to be recycled, causing the system_process process to hang out.
Although some system programs, it seems that it can be automatically unregistered (of course, not in time), but we should still clear in our program to unregister, the end of the program should be all the registration is canceled.
1.2 Memory leaks caused by objects not cleaned in the collection
We usually add references to some objects to the collection, and when we don't need the object, we don't clean up its references from the collection, so the collection gets bigger. If the set is static, the situation is even worse.
Ii. memory leaks due to resource object not shutting down
Resource objects such as (cursor,file files, etc.) often use some buffering, we should close them in time when we are not in use, so that their buffers can recover memory in time. Their buffering exists not only in the Java Virtual machine, but also outside the Java Virtual machine. If we simply set its reference to null without shutting them down, it often causes a memory leak. Because some resource objects, such as Sqlitecursor (in the destructor Finalize (), if we do not close it, it itself will close () closed), if we do not close it, the system will be recycled it also closed it, but this is too low efficiency. Therefore, when the resource object is not in use, it should call its close () function, close it, and then set it to null. Be sure that our resource objects are closed when our program exits.
The process of querying the database is often done, but there are often cases where the cursor is not closed after it has been used. If our query result set is relatively small, the memory consumption is not easy to find, only in the case of a large number of operations in a constant time to reproduce the memory problem, which will give future testing and troubleshooting difficulties and risks.
Third, some bad code into memory pressure
Some code does not cause memory leaks, but they do not use the memory of the effective and timely release, or do not effectively use the existing objects but frequent application of new memory, the memory of the recovery and allocation of large impact, it is easy to force the virtual machine to allocate more memory for the application process, Cause unnecessary memory expenses.
3.1,bitmap did not call recycle ()
When the bitmap object is not in use, we should call recycle () to free the memory before it is set to null. Although recycle () from the source, it should be able to immediately release Bitmap's main memory, but the test results show that it does not immediately release memory. But I should still be able to greatly accelerate the release of bitmap's main memory.
3.2, when constructing adapter, no cached Convertview is used
In order to construct the baseadapter of the ListView as an example, a method is proposed in the Baseadapter:
public view GetView (int position, view Convertview, ViewGroup parent) gives the ListView the View object that is required for each item. Initially, the ListView instantiates a certain number of view objects from the Baseadapter based on the current screen layout, and the ListView caches the View objects. When you scroll up the ListView, the View object that was originally on the top list item is recycled and then used to construct the newly-appearing list item. This construction process is done by the GetView () method, and the second parameter view convertview of GetView () is the view object of the cached list item (the cache does not have a view object when it is initialized, and Convertview is null.) )。
It can be seen that if we do not use Convertview, but each time in the GetView () to re-instantiate a view object, that is, waste of time, also caused by memory garbage, to increase the pressure on garbage collection, if garbage collection too late, The virtual machine will have to allocate more memory to the application process, resulting in unnecessary memory overhead. The process of retrieving the View object of the list item can be viewed by the ListView:
View Plaincopy to Clipboardprint?
Android.widget.AbsListView.java-to-void Addscrapview (View scrap) method.
Example code:
1 public View GetView (int position, view Convertview, ViewGroup parent) { 2 3 View view = new Xxx (...); 4 5 ... 6 7 return view; 8 9}
To fix the sample code:
Android Memory Management
1 public view GetView (int position, view Convertview, ViewGroup parent) { 2 3 view view = null; 4 5 if (Convertview! = null) { 6 7 view = Convertview; 8 9 populate (view, GetItem (position)); Ten ... () else {+ + view = new Xxx (...); ... * + return view; 22 23}
Overview:
In the development of Android, the main memory allocation and garbage collection at all times, because the system for each Dalvik virtual machine allocation of memory is limited, in Google's G1, the allocation of the largest heap size is only 16M, and later the machine is generally 24M, is very little poor. This requires us to always be aware of the development process. Do not cause oom errors due to your own code problems.
Memory Management for Java:
As you all know, the Android application layer is developed by Java, and Android's Davlik virtual machine is similar to the JVM, except that it is register-based. So to understand the memory management of Android it is necessary to understand the memory allocation and garbage collection mechanism of java.
In Java, the object is allocated memory through the new keyword, and the release of the memory is reclaimed by the garbage collector (GC), and the engineer does not need to explicitly manage the memory during development. However, it is possible to unknowingly waste a lot of memory, resulting in the Java Virtual machine to spend a lot of time to garbage collection, more serious is caused by the JVM Oom. Therefore, it is necessary for Java engineers to understand the memory allocation and garbage collection mechanisms of Java.
内存结构file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ksohtml/wps_clip_image-6926.png上面这张图是JVM的结构图,它主要四个部分组成:Class Loader子系统和执行引擎,运行时方法区和本地方法区,我们主要来看下RUNTIME DATA AREA区,也就是我们常说的JVM内存。可以看出,RUNTIMEDATA AREA区主要由5个部分组成:· Method Area:被装载的class的元信息存储在Method Area中,它是线程共享的· Heap(堆):一个java虚拟机实例中只存在一个堆空间,存放一些对象信息,它是线程共享的· Java栈: java虚拟机直接对java栈进行两种操作,以帧为单位的压栈和出栈(非线程共享)· 程序计数器(非线程共享)· 本地方法栈(非线程共享)JVM的垃圾回收(GC)file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ksohtml/wps_clip_image-12485.pngJVM的垃圾原理是这样的,它把对象分为年轻代(Young)、年老代(Tenured)、持久代(Perm),对不同生命周期的对象使用不同的垃圾回收算法。· 年轻代(Young)年轻代分为三个区,一个eden区,两个Survivor区。程序中生成的大部分新的对象都在Eden区中,当Eden区满时,还存活的对象将被复制到其中一个Survivor区,当此Survivor区的对象占用空间满了时,此区存活的对象又被复制到另外一个Survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制到年老代。· 年老代(Tenured)年老代存放的是上面年轻代复制过来的对象,也就是在年轻代中还存活的对象,并且区满了复制过来的。一般来说,年老代中的对象生命周期都比较长。· 持久代(Perm)用于存放静态的类和方法,持久代对垃圾回收没有显著的影响。Android中内存泄露监测在了解了JVM的内存管理后,我们再回过头来看看,在android中应该怎样来监测内存,从而看在应用中是否存在内存分配和垃圾回收问题而造成内存泄露情况。在android中,有一个相对来说还不错的工具,可以用来监测内存是否存在泄露情况:DDMS—Heapfile:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ksohtml/wps_clip_image-22715.png使用方法比较简单:· 选择DDMS视图,并打开Devices视图和Heap视图· 点击选择要监控的进程,比如:中我选择的是system_process· 选中Devices视图界面上的"update heap"图标· 点击Heap视图中的"Cause GC"按钮(相当于向虚拟机发送了一次GC请求的操作)在Heap视图中选择想要监控的Type,一般我们会观察dataobject的 total size的变化,正常情况下total size的值会稳定在一个有限的范围内,也就说程序中的代码良好,没有造成程序中的对象不被回收的情况。如果代码中存在没有释放对象引用的情况,那么data object的total size在每次GC之后都不会有明显的回落,随着操作次数的增加而total size也在不断的增加。(说明:选择好data object后,不断的操作应用,这样才可以看出total size的变化)。如果totalsize确实是在不断增加而没有回落,说明程序中有没有被释放的资源引用。那么我们应该怎么来定位呢?Android中内存泄露定位Mat(memory analyzer tools)是我们常用的用来定位内存泄露的工具,如果你使用ADT,并且安装了MAT的eclipse插件,你需要做的是进入DDMS视图的Devices视图:file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ksohtml/wps_clip_image-2165.png点击"dump HPROF file"按钮,然后使用MAT分析下载下来的文件。file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ksohtml/wps_clip_image-6565.png |
Here is a list of the problems, click Detail to go in, will be listed in detail, there may be problems in the code:
File:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ksohtml/wps_clip_image-32625.png
File:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ksohtml/wps_clip_image-21158.png
For the use of mat, refer to: http://www.blogjava.net/rosen/.... Html
The brother writes in more detail.
Summarize
Whether it's Java or Android, you should understand the memory allocation and garbage collection mechanism, the engineer to write code without bad code is difficult, the key is in the case of problems, how to troubleshoot the Android memory optimization
First, the memory mechanism of Android
Android programs are written in the Java language, so Android's memory management is similar to Java's memory management. The programmer allocates memory for the object through new, and all objects allocate space within the Java heap, while the object's release is done by the garbage collector. C + + memory mechanism is "who pollution, who governance", Java is more humane, give us a dedicated cleaner (GC).
So how can a GC confirm that an object has been discarded? Java uses the principle of a forward graph. Java considers the reference relationship as a directed edge of the graph, and has a pointing edge from the referrer to the Reference object. The thread object can serve as the starting vertex of a forward graph, which is a tree starting from the starting vertex, the objects that the root vertices can reach are valid objects, and the GC does not reclaim those objects. If an object (connected sub-graph) and this root vertex are unreachable (note that the graph is a forward graph), then we think that this (these) objects are no longer referenced and can be recycled by GC.
Second, the memory overflow of Android
How does the memory overflow of Android occur?
Android virtual machine is a register-based Dalvik, its maximum heap size is generally 16M, and some machines are 24M. So the amount of memory space we can use is limited. OutOfMemory errors occur if our memory footprint exceeds a certain level.
Why is there a situation where memory is not enough? I think there are two main reasons:
Due to our program errors, long-term maintenance of certain resources (such as the context) of the reference, resulting in memory leaks, resources caused by the failure to release.
Multiple objects that consume too much memory (such as bitmap) are saved, causing memory to exceed the limit.
Three, the evil of the static
Static is a keyword in Java that, when used to decorate a member variable, belongs to that class, not an instance of that class. So with the static modified variable, its life cycle is very long, if it is used to reference some resources to consume too many instances (the context of the most cases), then it should be treated with caution.
1 public class ClassName { 2 3 private static Context Mcontext; 4 5 //Omit 6 7}
The code above is dangerous, if the activity is assigned to Mcontext. So even if the activity is OnDestroy, the activity will not be released because there is still a reference to the object that holds it.
Let's give an example of an Android document.
private static drawable Sbackground; @Override protected void onCreate (Bundle state) { super.oncreate (state); TextView label = new TextView (this); Label.settext ("Leaks is Bad"); if (Sbackground = = null) { Sbackground = getdrawable (R.drawable.large_bitmap); } Label.setbackgrounddrawable (sbackground); Setcontentview (label); }
Sbackground is a static variable, but we find that we don't explicitly save the Contex reference, but when drawable is connected to the view, drawable sets the view to a callback, Because the view is a reference to the context, in fact we still have a reference to the context. This reference chain is as follows:
Drawable->textview->context
So, eventually the context was not released, and a memory leak occurred.
How can we effectively avoid the occurrence of such a reference?
You should avoid static member variables referencing resources that are consuming too many instances, such as context.
The context tries to use application context as much as possible because the application context has a longer life cycle, and it does not issue a memory leak.
Use WeakReference instead of strong references. For example, you can use weakreference<context> mcontextref;
The details of this section can also refer to the article section of the Android documentation.
All threads are the bane of the cause.
Threads are also an important source of memory leaks. The main reason for a thread's memory leak is that the thread life cycle is not controllable. Let's consider the following section of code.
1 public class MyActivity extends Activity { 2 3 @Override 4 5 public void OnCreate ( Bundle savedinstancestate) { 6 7 super.oncreate (savedinstancestate); 8 9 setcontentview (r.layout.main); new MyThread (). Start (); The private class MyThread extends thread{ @Override , public void Run () { super.run (); //do somthing) 29 30}
This code is very common and simple, it is the form that we often use. Let's think of a problem: assuming that the mythread run function is a time-consuming operation, when we turn on the thread, we turn the device's horizontal screen into a vertical screen, and normally the activity is recreated when the screen is converted, as we thought, the old activity should be destroyed. However, this is not the case in fact.
Since our thread is the inner class of activity, a reference to activity is saved in Mythread, and when Mythread's run function does not end, Mythread is not destroyed, so the old activity it references is not destroyed. Therefore, there is a memory leak problem.
File:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/ksohtml/wps_clip_image-6439.png
Some people like to use Android-provided asynctask, but in fact the asynctask problem is even more serious, and thread only has this memory leak problem when the run function does not end. However, the implementation mechanism within the asynctask is the use of threadpoolexcutor, the life cycle of the thread object produced by this class is indeterminate and is beyond the control of the application, so if Asynctask is the inner class of activity, The problem of memory leaks is more likely.
How should the memory leak problem caused by this thread be resolved?
Changes the internal class of a thread to a static inner class.
A weak reference is used inside the thread to hold the context reference.
The model is resolved as follows:
1 public abstract class Weakasynctask<params, Progress, Result, weaktarget> extends 2 asynctask<params , Progress, result> {3 protected weakreference<weaktarget> mtarget; 4 5 public Weakasynctask (Weaktarget target) {6 mtarget = new weakreference<weaktarget> (target); 7} 8 9/** {@inheritDoc} */@Override protected final void OnPreExecute () {fin Al 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) {This.doinbackground return (target, params); "Else {") "return null; +/** {@inheritDoc} */@Override Protected final void OnPostExecute (result result) {final Weaktarget target = Mtarget.get (); if (target! = null) {This.onpostexecute (target, result); protected void OnPreExecute (Weaktarget target) {//No default Action 4 0} protected abstract Result Doinbackground (weaktarget target, params ... params); protected void OnPostExecute (weaktarget target, result result) {//No default action 46} 47}
In fact, threading problems are not just memory leaks, but they can also lead to catastrophic problems. Because this article discusses memory issues, there is no discussion here.
Because 51cto didn't let me pass, said I have too many words, so separate pass.
Five, super Big Fat bitmap
It can be said that the majority of people who appear outofmemory problems are because of bitmap problems. Because bitmap occupies too much memory, it is a "super fat", especially the resolution of large pictures, if you want to display more than the problem is more significant.
How to solve the memory problem that bitmap brings to us?
Timely destruction.
Although the system is able to confirm that the memory allocated by bitmap will eventually be destroyed, it is likely to exceed the Java heap limit because it consumes too much memory. Therefore, in the use of bitmap, should be timely recycle off. Recycle is not sure that the bitmap will be released immediately, but will give the virtual machine a hint: "The picture can be released."
Set a certain sample rate.
Sometimes, we want to show the area is very small, there is no need to load the entire picture, and only need to record a reduced image, when you can set a certain sampling rate, then you can greatly reduce the memory occupied. As in the following code:
1 private ImageView Preview; 2 3 4 bitmapfactory.options Options = new Bitmapfactory.options (); 5 6 7 options.insamplesize = 2;// The image width height is the original One-second, that is, the picture is the original One-fourth 8 9 Bitmap Bitmap = Bitmapfactory.decodestream (Cr.openinputstream (URI), null, options); Ten Preview.setimagebitmap (bitmap);
Clever use of soft references (softrefrence)
Sometimes we don't keep a reference to it after we use bitmap, so we can't call the Recycle function. By using soft references skillfully, the bitmap can be effectively released when the memory is not fast enough. The following example:
/** This example for bloggers to write, to illustrate the usage, not verified */
1 private class Myadapter extends Baseadapter {2 3 private arraylist<softreference<bitmap>> MBITM Aprefs = new arraylist<softreference<bitmap>> (); 4 private arraylist<value> mvalues; 5 Private Context Mcontext; 6 private Layoutinflater Minflater; 7 8 Myadapter (context context, arraylist<value> values) {9 Mcontext = context; Ten mvalues = values; One minflater = (layoutinflater) context.getsystemservice (Context.layout_inflater_service); The public int GetCount () {return mvalues.size (); + Public Object getItem (int i) {mvalues.get return (i); (+) public long getitemid (int i) {return i; * Public view GetView (int i, view view, ViewGroup viewgroup) {View n Ewview = null; 26 if (view = null) {Newview = view; The else {Newview = (View) minflater.inflate (R.layout.image_view, false); Bitmap Bitmap = Bitmapfactory.decodefile (Mvalues.get (i). FileName); Mbitmaprefs.add (New softreference<bitmap> (Bitmap)); Join ArrayList (ImageView) newview here. Setimagebitmap (bitmap); return newview; 37} 38}
Six, the whereabouts of the strange cursor
The cursor is a class that manages the collection of data after the Android query data, and under normal circumstances there is no memory problem if the query gets a small amount of data, and the virtual machine can guarantee that the Cusor will eventually be released.
However, if the cursor has a large data volume, especially if there is blob information in it, it should be ensured that the memory occupied by the cursor is released in a timely manner rather than waiting for the GC to handle it. And Android is obviously prone to the programmer manually close the cursor, because in the source code we find that if we wait for the garbage collector to recycle, the user will be given an error.
So the way we use the cursor is generally as follows:
1 cursor cursor = NULL; 2 try { 3 cursor = mcontext.getcontentresolver (). Query (Uri,null, null,null,null); 4 if (cursor! = NULL) { 5 cursor.movetofirst (); 6 //do something 7 } 8 } catch (Exception e) { 9 e.printstacktrace (); Ten } finally { one (cursor! = null) { cursor.close (); 14}
In one case, we can't just close the cursor, which is the case in CursorAdapter, but notice that CursorAdapter does not automatically close the cursor at the end of the acivity, so You need to close it manually in the OnDestroy function.
1 protected void OnDestroy () { 2 3 if (madapter! = null && MADAPTER.GETCUROSR ()! = null) { 4 5 madapter.getcursor (). Close (); 6 7 } 8 9 Super.ondestroy (); 10 11}
The Changecursor function in CursorAdapter will release the original cursor and replace it with the new cursor, so you don't have to worry about the original cursor being closed.
You might think of using activity's managedquery to generate the cursor, so that the cursor will coincide with the acitivity's life cycle, and what a perfect solution! In fact, however, Managedquery also has a lot of limitations.
The cursor generated by managedquery must be guaranteed not to be replaced, because many programs may actually be uncertain about the query condition, so we often replace the cursor with the cursor of the new query. Therefore, the application of this method is also very small.
Seven, the other to say.
In fact, to reduce the use of memory, in fact there are many ways and requirements. For example, do not use the entire picture, try to use 9path images. Adapter to use Convertview and so on, a lot of details can save memory. These all need us to dig, who call Android's memory not to force again.
Android Development How to do memory optimization