Android effective solution to the problem of memory leaks example detailed _android

Source: Internet
Author: User
Tags anonymous log log message queue

Android is an effective solution to the problem of memory leaks

Android memory leak, I want to do the Android application when I encountered a headache, here is a good information I find on the Internet, examples of the solution to this problem

Foreword: Recently in studying handler knowledge, which involves a problem, how to avoid the memory overflow problem caused by handler. Find a lot of information on the Internet, there are a lot of copying each other, there is no practical role.

The memory leak detection tool in this article is: leakcanary GitHub address: https://github.com/square/leakcanary

What is a memory leak?

Memory leaks are memory failures that occur when the program is no longer in use, resulting in a useless memory consumption. Memory leaks do not mean that the physical memory disappears, where the memory leak is the value of the memory allocated by the program but due to the program logic error caused the program lost control of the memory, so that the memory waste.

how can a memory leak be caused?

Memory leaks caused by resource objects not being closed, such as not closing cursors after querying the database cursor

When constructing adapter, Convertview reuse is not used

Bitmap Object calls recycle () to free memory when used

An object is referenced by a long lifecycle object, such as an activity being referenced by a static collection that causes an activity not to be released

What is the harm of memory leak?

Memory leaks are not directly harmful to the app, and even if the app has a memory leak, it doesn't necessarily cause the app to crash, but it increases the footprint of the app's memory. Memory is not released, slowly causing the app memory overflow. so the purpose of our memory leak is to prevent the app from having a memory overflow.

1, the new thread caused by the activity memory leak

Example:

Package rxnet.zyj.com.myapplication;
 
Import android.support.v7.app.AppCompatActivity;
Import Android.os.Bundle;
Import Android.view.View;
 
public class Activity6 extends Appcompatactivity {
 
  @Override
  protected void onCreate (Bundle savedinstancestate ) {
    super.oncreate (savedinstancestate);
    Setcontentview (r.layout.activity_6);
 
    Findviewbyid (r.id.finish). Setonclicklistener (New View.onclicklistener () {
      @Override public
      void OnClick ( View v) {
        finish ();
      }
    });
 
    New Thread (New Runnable () {
      @Override public
      void Run () {
        try {<br>          //simulate time-consuming operations
          Thread.Sleep (15000);
        } catch (Interruptedexception e) {
          e.printstacktrace ();}}}
    ). Start ();
 
  }

After running the above code, click the Finish button, there is a memory leak after a while.

Why is there a memory leak in Activity6?

Enter the Activity6 interface, and then click the Finish button, Activity6 destroyed, but the Activity6 inside the thread is still running, anonymous internal class Runnable object refers to the Activity6 instance, The memory consumed by the ACTIVITY6 cannot be recycled by GC in a timely manner.

How to improve?

runnable change to static non-anonymous inner class.

Package rxnet.zyj.com.myapplication;
 
Import android.support.v7.app.AppCompatActivity;
Import Android.os.Bundle;
Import Android.view.View;
 
public class Activity6 extends Appcompatactivity {
 
  @Override
  protected void onCreate (Bundle savedinstancestate ) {
    super.oncreate (savedinstancestate);
    Setcontentview (r.layout.activity_6);
 
    Findviewbyid (r.id.finish). Setonclicklistener (New View.onclicklistener () {
      @Override public
      void OnClick ( View v) {
        finish ();
      }
    });
 
    New Thread (New Myrunnable ()). Start ();
 
  private static class Myrunnable implements Runnable {
 
    @Override public
    void Run () {
      try {
        Thread.Sleep (15000);
      } catch (Interruptedexception e) {
        e.printstacktrace ();}}}
   

2. Activity add listener cause activity memory leak

Package rxnet.zyj.com.myapplication;
 
Import android.app.Activity;
Import Android.os.Bundle;
 
public class Leakactivity extends activity {
  @Override
  protected void onCreate (Bundle savedinstancestate) {
    super.oncreate (savedinstancestate);
    Nastymanager.getinstance (). AddListener (this);
  }

This is an error that is often made in development, Nastymanager.getinstance () is a single example, when we bind the activity as Listener and Nastymanager through AddListener (this), Bad things happen.

How to improve?

To fix a Bug like this, it's pretty easy to get rid of him and Nastymanager when your acitivity is destroyed.

Package rxnet.zyj.com.myapplication;
 
Import android.app.Activity;
Import Android.os.Bundle;
 
public class Leakactivity extends activity {
  @Override
  protected void onCreate (Bundle savedinstancestate) {
    super.oncreate (savedinstancestate);
    Nastymanager.getinstance (). AddListener (this);
 
  @Override
  protected void OnDestroy () {
    Super.ondestroy ();
    Nastymanager.getinstance (). RemoveListener (this);
  }

3, Handler anonymous internal class caused memory overflow?

Look at a piece of code first.

Package rxnet.zyj.com.myapplication;
Import Android.os.Bundle;
Import Android.os.Handler;
Import Android.os.Message;
Import android.support.v7.app.AppCompatActivity;
Import Android.util.Log;
 
Import Android.view.View;
 
  public class Handleractivity extends Appcompatactivity {private final static int messagecode = 1; Private final Handler Handler = new Handler () {@Override public void Handlemessage (msg) {Super.hand
      Lemessage (msg);
    LOG.D ("Mmmmmmmm", "handler" + Msg.what);
 
  }
  };
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
 
    Setcontentview (R.layout.activity_handler);  Findviewbyid (r.id.finish). Setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View
      V) {finish ();
 
    }
    });
        New Thread (New Runnable () {@Override public void run () {handler.sendemptymessage (Messagecode);
      try {    Thread.Sleep (8000);
        catch (Interruptedexception e) {e.printstacktrace ();
      } handler.sendemptymessage (Messagecode);
 
  }). Start (); }
}

After this code is run, click the Finish button immediately and detect the memory leak from the handleractivity. When the activity is finished, the delay message continues to exist for 8 seconds in the main thread message queue, and then processes the message. The message refers to the handler object of the activity, and then the handler references the activity. These reference objects persist until the message is processed, causing the activity object to be recycled, causing the activity to be disclosed above. Handler is a very common and useful class, asynchronous, thread-safe, and so on. What happens if you have the following code? Handler.postdeslayed, suppose delay time is a few hours ... What does that mean? It means that as long as the message of handler is not finished, it survives and the activity that contains it lives on. We have to find a way to fix it, and the solution is weakreference, the so-called weak reference. When the garbage collector is recycled, it ignores the weak references, so the activity that contains it is cleaned out normally.

How to avoid

Using static inner classes

Using weak references

The modified code is like this.

Package rxnet.zyj.com.myapplication;
Import Android.os.Bundle;
Import Android.os.Handler;
Import Android.os.Message;
Import android.support.v7.app.AppCompatActivity;
Import Android.util.Log;
 
Import Android.view.View;
 
Import java.lang.ref.WeakReference;
  public class Handleractivity extends Appcompatactivity {private final static int messagecode = 1;
 
  private static Handler Handler;
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
 
    Setcontentview (R.layout.activity_handler);  Findviewbyid (r.id.finish). Setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View
      V) {finish ();
 
    }
    });
 
    Handler = new MyHandler (this);
        New Thread (New Runnable () {@Override public void run () {handler.sendemptymessage (Messagecode);
        try {thread.sleep (8000); catch (Interruptedexception e) {E.printstackTrace ();
      } handler.sendemptymessage (Messagecode);
 
  }). Start ();
 
    private static class MyHandler extends Handler {weakreference 

This handler already uses a static inner class and uses a weak reference. But this does not completely solve the problem of handleractivity memory leaks, the culprit is the way the thread was created, as in the first example of this article. The improved approach is to write the Runnable class as a static inner class.

The final complete code is as follows:

Package rxnet.zyj.com.myapplication;
Import Android.os.Bundle;
Import Android.os.Handler;
Import Android.os.Message;
Import android.support.v7.app.AppCompatActivity;
Import Android.util.Log;
 
Import Android.view.View;
 
Import java.lang.ref.WeakReference;
  public class Handleractivity extends Appcompatactivity {private final static int messagecode = 1;
 
  private static Handler Handler;
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
 
    Setcontentview (R.layout.activity_handler);  Findviewbyid (r.id.finish). Setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View
      V) {finish ();
 
    }
    });
 
    Create Handler handler = new MyHandler (this);
  Creates a thread and starts the thread new thread (new Myrunnable ()). Start ();
 
    private static class MyHandler extends Handler {weakreference 

Wait, it's not finished?

The above code has effectively solved the problem of handler,runnable referencing the activity instance, resulting in memory leaks, but this is not enough. Because the core reason for the memory leak is that this object should be reclaimed by the system, it is referenced by other objects, which cannot be recycled. So when we're writing code, we're going to always have this string. To go back to this question, when the current activity call finish is destroyed, in this activity all threads should not be in the Ondestory () method, cancel the thread. Of course, whether to cancel the asynchronous task, to see the specific requirements of the project, such as the destruction of the activity, start a thread, write log log to the local disk, in response to this need in the Ondestory () method to open the thread. So making a choice based on the current environment is the positive solution.

So we can also modify the code to: Remove all callback and message in OnDestroy ().

Package rxnet.zyj.com.myapplication;
Import Android.os.Bundle;
Import Android.os.Handler;
Import Android.os.Message;
Import android.support.v7.app.AppCompatActivity;
Import Android.util.Log;
 
Import Android.view.View;
 
Import java.lang.ref.WeakReference;
  public class Handleractivity extends Appcompatactivity {private final static int messagecode = 1;
 
  private static Handler Handler;
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
 
    Setcontentview (R.layout.activity_handler);  Findviewbyid (r.id.finish). Setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View
      V) {finish ();
 
    }
    });
 
    Create Handler handler = new MyHandler (this);
  Creates a thread and starts the thread new thread (new Myrunnable ()). Start ();
 
    private static class MyHandler extends Handler {weakreference 

4, Asynctask caused by memory leakage

Package rxnet.zyj.com.myapplication;
Import Android.os.AsyncTask;
Import android.support.v7.app.AppCompatActivity;
Import Android.os.Bundle;
Import Android.util.Log;
 
Import Android.view.View;
    public class Activity2 extends appcompatactivity {@Override protected void onCreate (Bundle savedinstancestate) {
    Super.oncreate (savedinstancestate);
 
    Setcontentview (r.layout.activity_2);  Findviewbyid (R.ID.FINISH2). Setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View
      V) {finish ();
 
 
    }
    });
        New Asynctask<string,integer,string> () {@Override protected string Doinbackground (String ... params) {
        try {thread.sleep (6000);
      catch (Interruptedexception e) {} return "SSSS";
        } @Override protected void OnPostExecute (String s) {Super.onpostexecute (s);
      LOG.D ("Mmmmmm activity2", "" + s); }}.executeonexecUtor (Asynctask.thread_pool_executor, ""); }
}

Why?

The above code creates an anonymous class asynctask in the activity, and the anonymous class and the non-static inner class hold the external class object, which is the activity, so if you declare and instantiate an anonymous Asynctask object in the activity, A memory leak may occur, and if the thread has been executing in the background after the activity has been destroyed, the thread will continue to hold the reference to the activity so that it will not be reclaimed by the GC until the thread executes.

How to solve?

Custom Static Asynctask Class A

The cycle of synctask is consistent with the activity cycle. That is to cancel the asynctask at the end of the activity lifecycle.

Package rxnet.zyj.com.myapplication;
Import Android.os.AsyncTask;
Import android.support.v7.app.AppCompatActivity;
Import Android.os.Bundle;
 
Import Android.view.View;
  public class Asynctaskactivity extends Appcompatactivity {private static mytask mytask;
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
 
    Setcontentview (R.layout.activity_asynctask); Findviewbyid (r.id.finish). Setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View
      V) {finish ();
 
    }
    });
    MyTask = new MyTask ();
 
  Mytask.executeonexecutor (Asynctask.thread_pool_executor, ""); private static class MyTask extends asynctask{@Override protected Object doinbackground (object[) params)
      {try {//Simulate time-consuming operation Thread.Sleep (15000);
      catch (Interruptedexception e) {e.printstacktrace ();
    Return ""; }} @Override Protected void OnDestroy () {Super.ondestroy ();
    Cancels the asynchronous task if (MyTask!= null) {Mytask.cancel (true); }
  }
}

5.Timer Tasks cause memory leaks

Package rxnet.zyj.com.myapplication;
 
Import Android.os.Bundle;
Import android.support.v7.app.AppCompatActivity;
Import Android.view.View;
 
Import Java.util.Timer;
Import Java.util.TimerTask;
 
public class Timeractivity extends Appcompatactivity {
 
  @Override
  protected void OnCreate (Bundle Savedinstancestate) {
    super.oncreate (savedinstancestate);
    Setcontentview (r.layout.activity_2);
 
    Findviewbyid (R.ID.FINISH2). Setonclicklistener (New View.onclicklistener () {
      @Override public
      void OnClick (View v) {
        finish ();
      }
    });
 
    Start Timer Task
    timer ();
 
  void Timer () {
    new timer (). Schedule (new TimerTask () {
      @Override public
      void Run () {while
        (true);
      }
    },1000); Start a task after 1 seconds
  }

why not?

The memory leak here is that the timer and TimerTask did not cancel, causing the timer and timertask to refer to external class activity all the time.

How to solve?

Cancel at the right time.

Static internal class for TimerTask

Note: See some information on the web that resolves timertask memory leaks can be used at the right time for cancel. After testing, it is proved that the use of cancel at the appropriate time, or there is a memory leak problem. So it must be used in conjunction with static internal classes.

Package rxnet.zyj.com.myapplication;
Import Android.os.Bundle;
Import android.support.v7.app.AppCompatActivity;
Import Android.util.Log;
 
Import Android.view.View;
Import Java.util.Timer;
 
Import Java.util.TimerTask;
 
  public class Timeractivity extends Appcompatactivity {private TimerTask timertask;
    @Override protected void OnCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate);
 
    Setcontentview (r.layout.activity_2);  Findviewbyid (R.ID.FINISH2). Setonclicklistener (New View.onclicklistener () {@Override public void OnClick (View
      V) {finish ();
 
    }
    });
  Start Timer task timer ();
    } void Timer () {timertask = new mytimertask (); New Timer (). Schedule (timertask, 1000); Start a task in 1 seconds} private static class Mytimertask extends timertask{@Override public void Run () {WHI
      Le (True) {LOG.D ("ttttttttt", "TimerTask");
@Override protected void OnDestroy ()}}} {    Super.ondestroy ();
    Cancels the timed task if (timertask!= null) {timertask.cancel (); }
  }
}

Thank you for reading, I hope to help you, thank you for your support for this site!

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.