Introduction to Android memory leaks, typical scenarios, and detection solutions

Source: Internet
Author: User

What is a memory leak?

The root search algorithm is used for garbage collection of Android virtual machines. The GC will traverse the heap starting from the root node (GC Roots). In the end, some of the garbage that is not directly or indirectly referenced to GC roots is reclaimed by GC. A memory leak is a process in which some objects (garbage objects) are no longer useful, but they can be referenced directly or indirectly to GC roots resulting in the inability to be recycled by GC. Useless objects occupy memory space, resulting in the inability to reclaim the memory occupied by this object in a timely manner. When memory leaks accumulate beyond the Dalvik heap size, oom (OutOfMemory) occurs.

Classic scenes of memory leaks static instances of non-static inner classes

Because the inner class holds a reference to an external class by default, the static instance belongs to the class. Therefore, when an external class is destroyed, the inner class still holds a reference to the external class, causing the outer class to not be recycled by the GC. Thus causing a memory leak.

Give me a chestnut.
    private static Leak mLeak;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        mLeak = new Leak();    }    class Leak {    }

Error chestnut Description: The static keyword Modifier mLeak property, which will mLeak exist in the static zone, and Leak as an inner class, holds a reference to the external class by default. When Activity destroyed, mLeak tightly hug Activity thigh affectionate confession: "mlgb! Labor is not let you go!" ”。 Bucket mLeak is not the property of the GC, naturally do not dare to recycle second-hand chicks Activity . Thus causing a memory leak.

Incorrect handler

Error code example:

    private MyHandler mMyHandler;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        mMyHandler = new MyHandler();        mMyHandler.sendMessageDelayed(new Message(), 10 * 1000);    }    class MyHandler extends Handler {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);        }    }

The correct wording is as follows:

    private MyHandler mMyHandler;    static class MyHandler extends Handler {        WeakReference<Activity> mActivityWeak;        MyHandler(Activity act) {            mActivityWeak = new WeakReference<Activity>(act);        }        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if (mActivityWeak.get() != null) {                // doSomething            }        }    }

We know handler.sendMessage(msg) when, msg.target will point handler to, msg will insert MessageQueue . This is the basis for the following explanation, this part of the students who are not familiar with this blog can refer to.

The wrong place

MyHandler is an inner class that holds a reference to an external class by default. ActivityIf MessageQueue There are still unhandled messages in the destroy, the mMyHandler example will continue to exist. While mMyHandler holding Activity the reference. Activitycannot be recycled by GC.

Correct parsing

staticKeyword to decorate the MyHandler class so that MyHandler does not hold references to external classes. Use WeakReference<activity> guarantees when
activityAfter destruction, the memory space occupied by GC reclamation is not delayed and activity can be referenced before being destroyed activity .

It's right to make it right.

From the above analysis, it can be concluded that handler caused the memory leak, because MessageQueue there is still to be processed Message , then we have to Activity#onDestroy() remove all the messages are not finished. Anyway Activity destroyed, MessageQueue in the meaning of msg what exists, can be removed. The code is as follows:

    @Override    protected void onDestroy() {        super.onDestroy();        // 移除所有的callback和msg        mMyHandler.removeCallbacksAndMessages(null);    }
Static variables cause memory leaks

Here is an example of a context leak caused by a singleton pattern

public class Singleton {    private static Singleton instance;    private Singleton(Context context){    }    public static Singleton getInstance(Context context){        if (instance == null){            synchronized (Singleton.class){                if (instance == null){                    instance = new Singleton(context);                }            }        }        return instance;    }}
The wrong place

In the calling Singleton#getInstance() method if it is passed in Activity . If instance not released, then this Activity will always exist. Thus causing a memory leak.

Repair Genuine

It will be new Singleton(context) changed new Singleton(context.getApplicationContext()) so that it Activity has no relation with the incoming. The release of the release, the home home.

Break it up and read
    • Cursor File Socket buffers are often used when resources are used, and so on. You should close them in time when they are not needed and reclaim the amount of memory they occupy.
    • BitmapDon't recycle drop it. Note that recycle after the call does not mean immediately recycle , just tell the virtual machine: Boy, it's time to work!
    • ListViewBe sure to use ConvertView andViewHolder
    • BraodcastReceiverRegistration is done, you need to reverse registration
Memory Leak Detection Heap tool
    1. Open DDMS View
    2. Select a specific application under devices
    3. Select the second little green dot update Heap under devices
    4. Keep running the program and click Cause GC
    5. Follow the data object row, toal size column
    6. Play with your app and if you find toal size getting bigger and larger, there's probably a memory leak happening
The MAT (Memory Analyzer tool) tools export. hprof file
    1. Open DDMS View
    2. Select a specific application under devices
    3. Select the second little green dot update Heap under devices
    4. Click Cause GC
    5. Click Dump HPROF File
    6. Switch to the Mat page card, as shown by default

The most conspicuous is the pie chart, which lists the size of each type of data. And the Red Arrow refers to the dominator of a spell, however this does not have any eggs. Our focus is on the histogram. Don't say anything, click on it. The default diagram is as follows

The default is sort by class, and the first line supports regular expressions. For easy viewing, we'll group by the group by package. The right way to open it should be like this.

Memory Leak Demo

Here is a static instance of the non-static inner class, for example, the demo has only two activity, MainActivity only one button, click Jump to SecondActivity .

public class SecondActivity extends Activity {    private static Leak mLeak;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_second);        mLeak = new Leak();    }    class Leak {    }}
Find memory leaks

Launch the app, click Enter SecondActivity , then press the Back button to return to MainActivity . Open the .hprof file. Look for our package name com.dyk.memoryleak .

As you can see, although we are finished SecondActivity , but SecondActivity still exist, memory leaks no doubt.

1. Right SecondActivity -click, select- List Objectswith incoming references

Results such as:

2. Right com.dyk.memoryleak.SecondActivity -click, select- Path to GCwith all references

Results such as:

You can see that the reference to the Mleak property is causing the SecondActivity collection to fail. Now that we have found the cause of the memory leak, I believe it is not very difficult to change it by the above introduction.

3. Enter again SecondActivity . Since the last creation has SecondActivity not yet been reclaimed, you can expect that there should be two instances at this time SecondActivity .

The contents of the memory leak are over for the time being. Mat For more features, please find your own learning. Thanks for the patience to read the last ~

Introduction to Android memory leaks, typical scenarios, and detection solutions

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.