Android Common memory leaks

Source: Internet
Author: User

Objective

For memory leaks, I think we have all experienced in development, except that memory leaks are not visible to us because they are active in the heap, and to detect memory leaks in programs, we can often use tools like Leakcanary, mat, and so on to detect memory leaks in applications. , Mat is a powerful memory analysis tool that is versatile and complex, while Leakcanary is a lightweight third-party memory leak detection tool by square open source, when it detects a memory leak in the program, It will be the most intuitive way to tell us who generated the memory leak and the memory leak caused who leaked it and could not be recycled for us to review.

Why are memory leaks generating memory leaks?

A memory leak occurs when an object is no longer needed and should be recycled, while another object that is being used holds its reference so that it cannot be recycled, which causes the object to be reclaimed to remain in the heap memory without being recycled.

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 limited memory for each application, and when a memory leak occurs in an application, it inevitably causes the application to exceed the memory limit allocated by the system, which results in a memory overflow and the application crash.

Memory leaks caused by a common memory leak summary singleton in Android

The singleton mode is very popular with developers, but using inappropriate words can also cause memory leaks, because the static nature of the singleton makes the life cycle of the singleton as long as the lifetime of the application, which means that if an object is no longer needed, the Singleton object also holds a reference to the object. Then this object will not be properly recycled, which results in a memory leak.

The following example:

public class AppManager {    private static AppManager instance;    private Context 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 an ordinary singleton pattern, and when this singleton is created, the length of the context's life cycle is critical because of the need to pass in a context:

    1. The application context: This will have no problem, because the life cycle of the singleton is as long as the application
    2. The context of the activity is passed in: When the context's activity exits, because the context is as long as the activity's life cycle (activity indirectly inherits from the context), So the current activity exits when its memory is not recycled because the Singleton object holds a reference to the activity.

So the correct singleton should be modified to the following way:

public class AppManager {    private static AppManager instance;    private Context 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 way, no matter what context is passed in, the application context will eventually be used, and the life cycle of the singleton is as long as the application, thus preventing a memory leak

Non-static inner class creates a memory leak caused by a static instance

There are times when we may be able to start frequent activity, in order to avoid duplicating the same data resources, this might be the case:

 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 (mresource = null) {mresource = new testresource (); } //...} class testresource {//...}}   

This creates a single instance of a non-static inner class within the activity, which uses the singleton data every time the activity is started, which avoids duplication of resources, but is a memory leak because non-static inner classes hold references to external classes by default. The non-static inner class is used to create a static instance with the same life cycle as the application, which causes the static instance to hold a reference to the activity, causing the memory resource of the activity not to be recycled properly. The right approach is:
Set the inner class as a static inner class or extract the inner class into a single case, if you need to use the context, use the ApplicationContext

Memory leaks caused by handler

Handler the use of memory leaks caused by the most common, usually in the processing of network tasks or encapsulation of some request callback API should be handled by handler, for handler code to write a non-standard is likely to cause a memory leak, the following example:

Publicclass mainactivity extends appcompatactivity {private handler Mhandler = new handler () { @Override public void Handlemessage ( Span class= "type" >message 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 handler causes a memory leak, because Mhandler is an instance of the handler non-static anonymous inner class, so it holds a reference to the external class activity, and we know that Message Queuing is constantly polling for processing messages in a looper thread. So when this activity exits, there is an unhandled message in the message queue, or a message is being processed, and the message in messages queue holds a reference to the Mhandler instance, and Mhandler holds a reference to the activity. Therefore, the memory resources of the activity cannot be reclaimed in a timely manner, causing a memory leak, so another approach is:

PublicClassMainactivityExtendsappcompatactivity {PrivateMyHandler Mhandler =NewMyHandler (this);PrivateTextView Mtextview;private staticClassMyHandlerExtendsHandler {Privateweakreference<Context> reference; PublicMyHandler (Context context) {reference =NewWeakreference<> (context); } @Override public void Handlemessage (message 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); }} 

Create a static handler inner class, and then use weak references to objects held by handler so that the objects held by the handler can be reclaimed at the time of collection, so that the activity leaks are avoided, but messages in the Looper thread's message queue may still be pending. So we should remove the message in the message queue at the time of the activity's destroy or stop, more precisely as follows:

PublicClassMainactivityExtendsappcompatactivity {PrivateMyHandler Mhandler =NewMyHandler (this);PrivateTextView Mtextview;private staticClassMyHandlerExtendsHandler {Privateweakreference<Context> reference; PublicMyHandler (Context context) {reference =NewWeakreference<> (context); }@Override public void Handlemessage (Message 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) 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

The memory leaks caused by threads are also common, and asynchronous tasks and runnable are an anonymous inner class, so they have an implicit reference to the current activity. If the task is not completed before the activity is destroyed,
The memory resource that will cause activity is not recycled, causing a memory leak. The correct approach is to use static internal classes in the following way:

StaticClassMyasynctaskExtendsasynctask<Void,Void,void> {Private weakreference<context> WeakReference;PublicMyasynctask(Context context) {WeakReference =New weakreference<> (context); }@OverrideProtected VoidDoinbackground(Void ... params) {Systemclock.sleep (10000);ReturnNull }@OverrideProtectedvoidOnPostExecutesuper.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 (); span class= "keyword" >new myasynctask (this). Execute ();        

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

Memory leaks due to resource not shutting down

For use of resources such as Braodcastreceiver,contentobserver,file,cursor,stream,bitmap, should be closed or logged off when the activity is destroyed, otherwise these resources will not be recycled, Cause a memory leak.

Some suggestions
    1. For objects that have a longer life cycle than the activity, you should use ApplicationContext
    2. For non-static external member variables (such as: Context, View) that need to be used in static internal classes, you can use weak references in static inner classes to refer to variables of external classes to avoid memory leaks
    3. For objects that are no longer required to be used, the display assigns them null, such as calling recycle () before bitmap is used, and then assigning null
    4. Maintain sensitivity to the life cycle of an object, paying particular attention to the life cycle of Singleton, static objects, global collections, etc.
    5. For internal class objects with a life cycle that is longer than activity, and for internal classes that use member variables of external classes, you can avoid memory leaks by doing this:

      1. Change an inner class to a static inner class
      2. Use weak references in static inner classes to refer to member variables of external classes
    6. When it comes to context, consider applicationcontext, of course, it is not omnipotent, for some places must use the context of activity, for Application,service, The context scenario for activity three is as follows:

among them: NO1 indicates that application and service can initiate an activity, but a new task queue is created. For dialog, it is only in activity that you can create

Common Android Memory leaks

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.