Android develops memory leaks and workarounds for common activity

Source: Internet
Author: User

In this article, we talk about memory leaks and workarounds that are common in Android development, as the landlord mentions the memory leaks caused by the context. This article describes these kinds of memory leaks in the "why" and "How to" methods.
Before you begin, let's look at what a memory leak is.

What is a memory leak?

Memory leaks are memory failures that occur when the program is no longer in use, and memory consumption is useless. Memory leaks do not refer to physical memory loss, where memory leaks are values allocated by the program but due to program logic errors The program loses control of the memory and makes memory waste.

How does it cause a memory leak?
    • A memory leak caused by a resource object not being closed, such as a cursor cursor not closed after querying the database
    • When constructing adapter, no Convertview reuse is used
    • Bitmap object does not call recycle () to free memory when it is in use
    • Object is referenced by an object that has a long life cycle, such as activity being referenced by a static collection, causing activity to not be released

In the following space, we focus on memory leaks that are common to activity.

Memory leaks 1: quiescent activities (Static activities)

The code is as follows:
Mainactivity.java

 Public  class mainactivity extends appcompatactivity {    Private StaticMainactivity activity; TextView Sabutton;@Override    protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate);        Setcontentview (R.layout.activity_main);        Sabutton = (TextView) Findviewbyid (R.id.text); Sabutton.setonclicklistener (NewView.onclicklistener () {@Override  Public void OnClick(View v)                {setstaticactivity ();            Nextactivity ();    }        }); }voidSetstaticactivity () {activity = This; }voidNextactivity () {startactivity (NewIntent ( This, Registeractivity.class)); Systemclock.sleep ( +);    Finish (); }@Override    protected void OnDestroy() {Super. OnDestroy ();//Use leakcanary to see if there is a memory leakMyapplication.getrefwatcher (). Watch ( This); }}

Leakcanary detected memory leaks:

why not?
In the above code, we declare a static activity variable and refer to the currently running activity instance in the TextView onclick event, so if the reference is not cleared before the end of the activity's life cycle, it will cause a memory leak. Because the declared activity is static, the memory is resident, and if the object is not purged, the garbage collector cannot reclaim the variable.

How to solve?
The simplest method is to empty the static variable activity in the Ondestory method so that the garbage collector can recycle the static variable.

@Override    protectedvoidonDestroy() {        super.onDestroy();        null;        //使用LeakCanary观察是否有内存泄漏        MyApplication.getRefWatcher().watch(this);    }
memory leak 2: Static View

The code is as follows:
Mainactivity.java

...Private StaticView view; TextView Sabutton;@Override    protected void onCreate(Bundle savedinstancestate) {Super. OnCreate (Savedinstancestate);        Setcontentview (R.layout.activity_main);        Sabutton = (TextView) Findviewbyid (R.id.text); Sabutton.setonclicklistener (NewView.onclicklistener () {@Override  Public void OnClick(View v)                {Setstaticview ();            Nextactivity ();    }        }); }voidSetstaticview () {view = Findviewbyid (R.id.sv_view); }    ...

Leakcanary detected memory leaks

why not?
The above code seems to have no problem, declare a static variable view in activity, and then initialize, when the activity life cycle ends the memory is released, but Leakcanary shows a memory leak, why? The problem here is that, once the view is loaded into the interface, it will hold a reference to the context object, in this case the context object is our activity, declaring a static variable referencing the view, and referencing the activity, So when the activity life cycle is over, the static view is not erased, and the activity reference is held, so the memory leaks.

How to solve?
Empty the static variable in the OnDestroy method.

@OverrideprotectedvoidonDestroy() {    super.onDestroy();    null;    MyApplication.getRefWatcher().watch(this
Memory Leak 3: Inner class

The code is as follows:
Mainactivity.java

privatestatic Object inner;void createInnerClass() {    class InnerClass {    }    new InnerClass();}View icButton = findViewById(R.id.ic_button);icButton.setOnClickListener(new View.OnClickListener() {    @OverridepublicvoidonClick(View v) {        createInnerClass();        nextActivity();    }});

Memory leaks detected using leakcanary:

why not?
A non-static inner class holds a reference to an external class, in which the inner class holds a reference to the activity, so inner will always hold activity, and if the activity life cycle ends without clearing the reference, a memory leak occurs.

How to solve?
Because a non-static inner class implicitly holds a strong reference to an external class, we declare the inner class to be static.

void createInnerClass() {    static class InnerClass {    }    new InnerClass();}
Memory leak 4: Anonymous class
void  StartAsyncTask () {new  asynctask<void, Void, void> () { @Override  protected  Void  Doinbackground  (Void ... params) {while  (true        ); }}.execute ();} super . OnCreate (savedinstancestate); Setcontentview (R.layout.activity_main); View Aicbutton = Findviewbyid (R.id.at_button); Aicbutton.setonclicklistener (new  View.onclicklistener () { @Override  public         Span class= "Hljs-keyword" >void  onclick  (View v) {startasynctask ();    Nextactivity (); }});

Memory leaks detected using leakcanary:

why not?
The above code creates an anonymous class asynctask in activity, with the same anonymous class and non-static inner class, which holds the outer class object, which is the activity, so if you declare and instantiate an anonymous Asynctask object in activity, A memory leak can occur, and if the thread is still executing in the background after the activity is destroyed, the thread will continue to hold the activity reference so that it will not be recycled by the GC until the thread executes.

How to solve?
Customize the static Asynctask class and keep the asynctask cycle and activity cycle consistent, i.e. cancel the asynctask at the end of the activity life cycle.

Memory leak 5:handler

The code is as follows:
Mainactivity.java

...voidCreatehandler () {NewHandler () {@Override  Public void Handlemessage(Message message) {Super. handlemessage (message); }}.postdelayed (NewRunnable () {@Override  Public void Run() { while(true); }    }, +);} ... View Hbutton = Findviewbyid (R.id.h_button); Hbutton.setonclicklistener (NewView.onclicklistener () {@Override  Public void OnClick(View v)        {Createhandler ();    Nextactivity (); }});...

why not?
When Android application is started, the framework will first help us complete the message loop of the UI thread, that is, in the UI thread, loop, MessageQueue, These instances, such as message, have been implemented by the framework to help us. All application major events, such as activity life cycle methods, button click events, are included in this message, and the message is added to the MessageQueue, so The message loop of the UI thread runs through the entire application life cycle, so when you generate an instance of handler in the UI thread, you hold a reference to loops and MessageQueue. And there is a reference to the outer class inside the Java non-static inner class and anonymous, while the static inner class does not hold a reference to the outer class.

How to solve?
It can be seen from the above conclusion that the source of the leak is that the anonymous class holds the reference to the activity, so you can customize the handler and Runnable classes and declare them as static inner classes to disassociate and activity references.

Memory leak 6:thread

The code is as follows:
Mainactivity.java

void spawnThread() {    new Thread() {        @Overridepublicvoidrun() {            while(true);        }    }.start();}View tButton = findViewById(R.id.t_button);tButton.setOnClickListener(new View.OnClickListener() {  @OverridepublicvoidonClick(View v) {      spawnThread();      nextActivity();  }});

why not?
As with Asynctask, there is not much to repeat.

How to solve?
Can we customize the thread and declare it as static? In fact, this is not recommended, because the thread at the root of the GC, the DVM and all the active thread to maintain a hard references relationship, so the running thread will never be garbage collected by GC, So the correct solution is to add a cancellation mechanism to the thread based on the custom static inner class, so we can shut down the thread in the activity's OnDestroy method.

memory leaks 7:timer Tasks

The code is as follows:
Mainactivity.java

void  ScheduleTimer        () {new  Timer (). Schedule (new  timertask () {         @Override  public  void  run         () {while  (true ); }},1000 );} View Ttbutton = Findviewbyid (R.id.tt_button); Ttbutton.setonclicklistener (new  View.onclicklistener () { @Override  public         Span class= "Hljs-keyword" >void  onclick  (View v) {scheduletimer ();    Nextactivity (); }});

why not?
The memory leak here is that the timer and TimerTask do not cancel, causing the timer and TimerTask to always refer to the external class activity.

How to solve?
Cancel at the right time.

memory leaks 8:sensor Manager

The code is as follows:
Mainactivity.java

void        Registerlistener () {Sensormanager Sensormanager = (sensormanager) getsystemservice (Sensor_service);       Sensor sensor = Sensormanager.getdefaultsensor (Sensor.type_all); Sensormanager.registerlistener (this , sensor, Sensormanager.sensor_delay_ fastest);} View Smbutton = Findviewbyid (R.id.sm_button); Smbutton.setonclicklistener (new  View.onclicklistener () { @Override  public         Span class= "Hljs-keyword" >void  onclick  (View v) {registerlistener ();    Nextactivity (); }});

why not?
Call Getsystemservice through the context to get system services that run in their own processes performing a series of background work or interfaces that provide and hardware interaction, if the context object needs to be notified at any time when an internal service event occurs. You need to register yourself as a listener so that the service holds an activity, and if the developer forgets to log off the listener before the activity is destroyed, it causes a memory leak.

How to solve?
Unregisters the listener in the OnDestroy method.

Summarize

In development, the worst case of memory leaks is that the app runs out of memory and crashes, but often the real situation is not like this, instead it only consumes a lot of memory but does not flash back, allocates less memory, the GC will work more to free up memory, the GC is very time-consuming operation, so it will cause the page to lag. We must be aware of the potential memory leaks when instantiating an object in the activity, so be sure to check for memory leaks frequently.

Outside the question

In this article, the landlord uses Leakcanary to detect the memory leak. Leakcanary is a very useful third-party library for memory leak detection, and interested friends can check out the Leakcanary usage method and use it to monitor memory leaks in the app.

Android develops memory leaks and workarounds for common activity

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.