Common memory leaks and avoidance summaries in Android development

Source: Internet
Author: User
Tags anonymous message queue sleep static class

Why memory leaks occur

A memory leak occurs when an object does not need to be reused, it should be reclaimed, and another object in use holds its reference so that it cannot be reclaimed, which causes the object that should be reclaimed to not be recycled to stay in heap memory.


What is the impact of memory leaks on programs?

Memory leaks are one of the main causes of application Oom! We know that the Android system allocates a limited amount of memory for each application, and that when a memory leak in an application is more likely to occur, it will inevitably cause the application to exceed the memory limit allocated by the system, resulting in a memory overflow that results in application crash.


A common memory leak rollup in Android


A single example of a memory leak

The single case pattern is very popular with developers, however, improper use can also cause a memory leak, because the single example of the static characteristics of the life cycle and application life cycle as long, which means that if an object is no longer needed to use, and the single Case object also holds the object's reference, Then this object will not be recycled properly, which causes a memory leak. The following is a code example:

public class AppManager {
private static AppManager instance;
private context;
Private AppManager (context context) {
This.context = context;
}
public static AppManager getinstance (context context) {
if (instance!= null) {
Instance = new AppManager (context);
}
return instance;
}
}

This is a common single case pattern, and the length of the context's life cycle is critical when creating this single instance because of the need to pass in a context:

1, incoming is the context of application: This will have no problem, because the life cycle of the single example and application as long

2, the incoming is the context of activity: when the context of the corresponding activity exits, because the context and activity life cycle as long (activity indirectly inherited from the context), So when the current activity exits, its memory is not reclaimed because the single Instance object holds a reference to the activity.

So the correct single example should be modified to the following way:

public class AppManager {
private static AppManager instance;
private context;
Private AppManager (context context) {
This.context = Context.getapplicationcontext ();
}
public static AppManager getinstance (context context) {
if (instance!= null) {
Instance = new AppManager (context);
}
return instance;
}
}

This will eventually use the application context, regardless of the context in which it is passed in, and the life cycle of the single example is as long as it is applied, thus preventing memory leaks


Non-static internal classes Create a memory leak caused by static instances

There may be times when we may be able to create the same data resources in the active activity, in order to avoid duplication:

public class Mainactivity extends Appcompatactivity {
private static Testresource mresource = null;
@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.activity_main);
if (Mmanager = = null) {
Mmanager = new Testresource ();
}
//...
}
Class Testresource {
//...
}
}

This creates a single instance of a non-static inner class within the activity, which is used every time the activity is started, so that although the duplication of resources is avoided, this type of writing creates a memory leak, because the non-static inner class holds the reference to the external class by default. It also uses the non-static inner class to create a static instance with a lifetime of as long as the application, which causes the static instance to hold a reference to the activity all the time, causing the activity's memory resources to not be recycled properly. The correct approach is to set the inner class as a static inner class or to extract the inner class into a single example, and if you need to use the context, use the ApplicationContext


memory leaks caused by handler

Handler use of the memory leak problem should be said that the most common, usually in the processing of network tasks or encapsulation of some request callback and other APIs should be used to deal with handler, for handler use code to write an irregular is likely to cause memory leaks, the following example:

public class Mainactivity extends Appcompatactivity {
Private Handler Mhandler = new Handler () {
@Override
public void Handlemessage (msg) {
//...
}
};
@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.activity_main);
LoadData ();
}
private void LoadData () {
. Request
Message message = Message.obtain ();
Mhandler.sendmessage (message);
}
}

This way of creating a handler can cause a memory leak, because Mhandler is an instance of handler's Non-static anonymous inner class, so it holds references to external class activity, and we know that Message Queuing is constantly polling processing messages in a looper thread. So when the activity exits, there are still unhandled messages in the message queue or processing messages, while message queue messages hold references to Mhandler instances, Mhandler also hold activity references. So the memory resources that cause the activity cannot be recycled in time, causing a memory leak, so another approach is:

public class Mainactivity extends Appcompatactivity {
Private MyHandler Mhandler = new MyHandler (this);
Private TextView Mtextview;
private static class MyHandler extends Handler {
Private weakreference<context> reference;
Public MyHandler {
Reference = new Weakreference<> (context);
}
@Override
public void Handlemessage (msg) {
Mainactivity activity = (mainactivity) reference.get ();
if (activity!= null) {
Activity.mTextView.setText ("");
}
}
}
@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.activity_main);
Mtextview = (TextView) Findviewbyid (R.id.textview);
LoadData ();
}
private void LoadData () {
. Request
Message message = Message.obtain ();
Mhandler.sendmessage (message);
}
}

Creates a static handler inner class and then uses a weak reference to the objects held by handler so that the objects held by the handler can be recycled, so that although the activity leaks are avoided, the message queue of the Looper thread may still be pending messages. So we should remove messages from message queues when the activity is destroy or stop, and more accurately:

public class Mainactivity extends Appcompatactivity {
Private MyHandler Mhandler = new MyHandler (this);
Private TextView Mtextview;
private static class MyHandler extends Handler {
Private weakreference<context> reference;
Public MyHandler {
Reference = new Weakreference<> (context);
}
@Override
public void Handlemessage (msg) {
Mainactivity activity = (mainactivity) reference.get ();
if (activity!= null) {
Activity.mTextView.setText ("");
}
}
}
@Override
protected void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.activity_main);
Mtextview = (TextView) Findviewbyid (R.id.textview);
LoadData ();
}
private void LoadData () {
. Request
Message message = Message.obtain ();
Mhandler.sendmessage (message);
}
@Override
protected void OnDestroy () {
Super.ondestroy ();
Mhandler.removecallbacksandmessages (NULL);
}
}

Use Mhandler.removecallbacksandmessages (null); Is to remove all messages and all runnable in the message queue. Of course, you can also use Mhandler.removecallbacks () or mhandler.removemessages () to remove the specified runnable and message.


memory leaks caused by threads

Memory leaks caused by threads are also common, as the following two examples may be written by everyone:

—————— test1
New Asynctask<void, Void, void> () {
@Override
protected void Doinbackground (void ... params) {
Systemclock.sleep (10000);
return null;
}
}.execute ();
—————— test2
New Thread (New Runnable () {
@Override
public void Run () {
Systemclock.sleep (10000);
}
). Start ();

The above asynchronous task and runnable are both anonymous inner classes, so they have an implicit reference to the current activity. If the activity is not completed before it is destroyed, the memory resources of the event will not be recycled, causing a memory leak. The correct approach is to use static internal classes in the following ways:

Static class Myasynctask extends Asynctask<void, Void, void> {
Private weakreference<context> WeakReference;
Public Myasynctask {
WeakReference = new weakreference<> (context);
}
@Override
protected void Doinbackground (void ... params) {
Systemclock.sleep (10000);
return null;
}
@Override
protected void OnPostExecute (void avoid) {
Super.onpostexecute (avoid);
Mainactivity activity = (mainactivity) weakreference.get ();
if (activity!= null) {
//...
}
}
}
Static class Myrunnable implements runnable{
@Override
public void Run () {
Systemclock.sleep (10000);
}
}
——————
New Thread (New Myrunnable ()). Start ();
New Myasynctask (This). Execute ();

This avoids the activity of memory resource leakage, of course, in the destruction of the task should also cancel the corresponding tasks Asynctask::cancel (), to avoid the task in the background to waste resources.


Memory leak due to resource not shutdown

The use of resources such as braodcastreceiver,contentobserver,file,cursor,stream,bitmap should be closed or cancelled in time for the activity to be destroyed, otherwise these resources will not be recycled, caused a memory leak.


Some suggestions

1, for life cycle objects longer than the object if necessary should use ApplicationContext

2, when it comes to the context, first consider applicationcontext, of course, it is not omnipotent, for some places you have to use activity, for Application,service, The context of the activity three scenarios is as follows:
* * Where: **no1 means that application and service can start an activity, but need to create a new task queue. For dialog, only the activity can create

3, for the need in the static internal class to use non-static external member variables (such as: Context, View), you can use the weak reference in the static inner class to refer to the external class variables to avoid memory leaks

4. The internal class object that is longer than the activity, and the member variables of the external class are used in the inner class to avoid memory leaks:
Change inner class to static inner class
A weak reference is used in a static inner class to refer to a member variable of an external class

5, for no longer need to use the object, the display of its assigned to null, such as the use of bitmap after the first call recycle (), and then assigned to NULL6, to maintain the sensitivity of the object lifecycle, pay special attention to single cases, static objects, global set, etc. life cycle


Android performance optimization tips for avoiding memory leaks


1, for the life cycle longer than the object, if necessary should use ApplicationContext;

2, when it comes to the context, first consider applicationcontext, of course, it is not omnipotent, for some places you have to use activity, for Application,service, The context of the activity three scenarios is as follows:

* * Where: **no1 means that application and service can start an activity, but need to create a new task queue. For dialog, it can only be created in an activity.

3. For the need to use non-static external member variables (such as context, View) in static internal classes, you can use weak references in static inner classes to refer to variables of external classes to avoid memory leaks.

4. The internal class object that is longer than the activity, and the member variables of the external class are used in the inner class to avoid memory leaks:


1 change inner class to static inner class

2 the static inner class uses weak references to refer to the member variables of the outer class

5. For objects that no longer need to be used, the values shown are assigned null, such as recycle (), and then null, after using bitmap.

6, keep the object life cycle sensitive, pay special attention to single example, static object, global set, etc. life cycle.


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.