preface

  • inAndroidIn, the phenomenon of memory leak is very common; And the consequences of a memory leak can make the applicationCrash
  • This article provides a comprehensive overview of the nature, causes, and solutions of memory leaks, and finally provides some common memory leak analysis tools, which I hope you will enjoy.

directory


1. Introduction

  • namelyML (Memory Leak)
  • The phenomenon of memory not being released when it is no longer needed after a program has applied for it

2. Impact on applications

  • It is easy for the application to run out of memory, i.eOOM

Introduction to Memory Overflow:


3. The root cause of the memory leak

  • A detailed description

  • Particular attention from a mechanistic point of view, due toJavaExists garbage collection mechanism (GC), there should be no memory leak The cause of the memory leak is external human cause =The unconscious holding of object references makes the life cycle of the holder > the life cycle of the referenced

4. Basics: How Java manages memory

Java memory management = object/variable memory allocation + memory release

  • Object/variable memory allocation is the responsibility of the program
  • Object/variable memory is freed byJavaGarbage collector (GC)/frame stack

Next, the memory allocation & memory release strategy is discussed in detail

4.1 Memory Allocation Policy

  • There are three types of allocation: static allocation, stack allocation, & heap allocation, respectively for static variables, local variables & object instances
  • The details are as follows

Note: Use 1 example to explain memory allocation

Public class Sample {msample1&msample1&point to the object in the heap int s1 = 0; Sample mSample1 = new Sample(); / method/s2, mSample2 stored in the stack for local variables in memory / / variable mSample2 points to the object instance in a heap memory / / the members of the instance variable s1, mSample1 also stored in a stack of public voidmethod() { int s2 = 0; Sample mSample2 = new Sample(); } // mSample3 = new Sample(); // mSample3 = new Sample();Copy the code

4.2 Memory Release Policy

Object allocation (i.e., heap allocation) = Java Garbage Collector (GC)

Because static allocation does not need to release, stack allocation only through the frame stack automatically out and into the stack, it is simple, so do not describe in detail

  • JavaGarbage collector (GC) = garbage collection algorithm, mainly including:

  • The details are as follows


5. Common Causes and Solutions for memory Leaks

5.1 collection class

  • Cause of memory leak After an element is added to a collection class, the collection element object is still referenced. As a result, the collection element object cannot be reclaimed, resulting in a memory leak

  • Examples demonstrate

List List<Object> objectList = new ArrayList<>();for(int i = 0; i < 10; i++) { Object o = new Object(); objectList.add(o); o = null; } // Free the collection element reference itself: o=null) // But the collection List still references the object, so the garbage collector still cannot reclaim the objectCopy the code
  • After the collection element object is added to the solution Collection class, it must be removed from the collection after use

Since there are many elements in a collection, the simplest method = empty the collection object & and set it to null

ObjectList objectList.clear(); objectList=null;Copy the code

5.2 Member variables modified by the Static keyword

  • The lifetime of the member variable modified by the Static keyword = the lifetime of the application

  • Leak reason If made by the Static keyword modified member variables refer to expend resources too many instances, such as Context, is prone to life cycle of the member variable > reference instance lifecycle, when to end life cycle destroyed by examples, by Static variables hold and can’t be recycled, thus appeared memory leaks

  • Instance to explain

Public class ClassName {private static Context mContext; public class ClassName {private static Context mContext; / /... MContext = context; // A memory leak occurs when the Activity needs to be destroyed because mContext = static & life cycle = application life cycle}Copy the code
  • The solution
  1. Try to avoidStaticMember variables reference resources that consume too many instances (e.gContext)

If you need to refer to a Context, use the Context of Applicaiton whenever possible

  1. Using weak references(WeakReference)Hold instances instead of strong references

Note: A very typical example of static member variables is the = singleton pattern

  • Because of the static nature of the singleton pattern, the length of its life cycle equals the life cycle of the application

  • Leak Cause If an object is no longer needed and the singleton still holds a reference to the object, the object will not be reclaimed properly, resulting in a memory leak

  • Examples demonstrate

// When you create a singleton, you pass in a Context // If you pass in an Activity Context, then the singleton holds a reference to the Activity // Since the singleton holds a reference to the Activity (until the end of the application lifecycle), even if the Activity exits, The memory of the Activity will not be reclaimed // especially for large activities, OOM public class SingleInstanceClass {private static SingleInstanceClass; private Context mContext; private SingleInstanceClass(Context context) { this.mContext = context; } public SingleInstanceClass getInstance(context context) {if (instance == null) {
            instance = new SingleInstanceClass(context);
        }        
        returninstance; }}Copy the code
  • Life cycle of the object referenced by the solution singleton pattern = life cycle of the application

As in the example above, the Application Context should be passed because the Application lifecycle = the entire Application lifecycle

public class SingleInstanceClass { private static SingleInstanceClass instance; private Context mContext; private SingleInstanceClass(Context context) { this.mContext = context.getApplicationContext(); } public SingleInstanceClass getInstance(context context) {if (instance == null) {
            instance = new SingleInstanceClass(context);
        }        
        returninstance; }}Copy the code

5.3 Non-static inner classes/Anonymous classes

  • Non-static inner classes/anonymous classes hold references to external classes by default; Static inner classes do not
  • There are three common cases, which are: non-static instances of inner classes = static, multi-threading, messaging mechanism (Handler)

5.3.1 Instances of non-static inner classes = static

  • Cause of leak If the instance created by a non-static inner class is static (its life cycle = the life cycle of the application), the non-static inner class will hold references to the external class by default, which will cause memory leak

That is, a static object in an outer class that holds a non-static inner class

  • Examples demonstrate
// Background: a. Create a singleton of a non-static inner class inside the Activity to avoid creating the same data resource repeatedly. Public class TestActivity extends AppCompatActivity {// A reference to an instance of a non-static inner class // Note: Public static InnerClass InnerClass = null; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Ensure that there is only one instance of a non-static inner classif(innerClass == null) innerClass = new InnerClass(); } private class InnerClass {InnerClass... } // the cause of the memory leak is as follows: // a. When TestActivity is destroyed, the life cycle of the non-static innerClass singleton reference (innerClass) = the life cycle of the application, holding a reference to the external class TestActivity // b. Therefore, TestActivity cannot be reclaimed by GC, resulting in a memory leakCopy the code
  • The solution
    1. Set a non-static inner class to: Static inner class (Static inner classes do not hold references to external classes by default)
    2. The inner class is extracted and encapsulated as a singleton
    3. Try to avoid instances created by non-static inner classes = static

If you need to use Context, you are advised to use the Application Context

5.3.2 Multithreading: AsyncTask, implement Runnable interface, inherit Thread class

  • Multithreaded usage = non-static inner class/anonymous class; That is, the thread class is a non-static inner class/anonymous class
  • Cause of leak When the worker thread is processing a task & the external class needs to be destroyed, because the worker thread instance holds a reference to the external class, the external class cannot be collected by the garbage collector (GC), resulting in a memory leak
  1. Multithreading mainly uses the following:AsyncTask, implementation,RunnableInterface & InheritanceThreadclass
  2. The principle of the first three memory leaks is the same, here mainly to inheritanceThreadClass as an example
  • Examples demonstrate
*/ public class MainActivity extends AppCompatActivity {public static final String TAG ="carson:";
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main); New MyThread().start(); } private class MyThread extends Thread{@override public voidrun() {
                try {
                    Thread.sleep(5000);
                    Log.d(TAG, "Multithreading performed."); } catch (InterruptedException e) { e.printStackTrace(); }}}} /** * Mode 2: Anonymous Thread inner class */ public class MainActivity extends AppCompatActivity {public static final String TAG ="carson:";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // Implement multi-threaded new with an anonymous inner classThread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    Log.d(TAG, "Multithreading performed."); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); }} /** * */ // The worker Thread class is a non-static inner class/anonymous inner class, and by default it holds a reference to the external class // When the worker Thread is running, if the external class MainActivity needs to be destroyed // Because the worker Thread class instance holds a reference to the external class. Will prevent the external class from being collected by the garbage collector (GC), causing a memory leakCopy the code
  • As you can see above, there are two key conditions that can cause a memory leak:
  1. There is a reference relationship that the worker thread instance holds an external class reference
  2. Life cycle of the worker thread instance > Life cycle of the external class, where the worker thread is still running and the external class needs to be destroyed

Solution idea = make any of the above conditions is not true.

// There are two solutions: static inner class & when the outer class ends its lifecycle, the thread is forced to terminate. Static inner classes do not hold references to external classes by default, thus eliminating the "worker thread instance holds references to external classes" reference relationship */ public class MainActivity extends AppCompatActivity {public static final String TAG ="carson:";
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main); New MyThread().start(); } private static class MyThread extends Thread{@override public void public Override extends Thread{@override public void public voidrun() {
                try {
                    Thread.sleep(5000);
                    Log.d(TAG, "Multithreading performed."); } catch (InterruptedException e) { e.printStackTrace(); }}}} /** * Solution 2: Force thread termination when the external class terminates its lifecycle * Principle: Make the lifecycle of the worker thread instance synchronized with the lifecycle of the external class * Implementation: When an external class (Activity in this case) ends its lifecycle (onDestroy () is called), the thread is forced to terminate (stop () is called) */ @override protected voidonDestroy() { super.onDestroy(); Thread.stop(); // Force the thread to terminate at the end of the external Activity lifecycle}Copy the code

5.3.3 Message passing mechanism: Handler

Android memory Leak: A detailed explanation of the Handler memory leak

5.4 The Resource Object is Not Closed After Being used

  • Leak Cause Resources (such as broadcast BraodcastReceiver, File stream File, database Cursor, and picture resource Bitmap) will not be recovered if they are not shut down or logged out when the Activity is destroyed, causing a memory leak

  • The solution is to shut down/log off the resource when the Activity is destroyed

// For broadcast BraodcastReceiver: unregister unregisterReceiver() // For stream File: Close () // For database cursor: close cursor. Close () // For image resource Bitmap: Android only allocates 8M memory for images. If a Bitmap object occupies too much memory, call recycle() to reclaim the memory occupied by the pixel of the object when it is no longer used. And then null bitmap.recycle (); Bitmap = null;Copy the code

5.5 Other Uses

  • In addition to the above four common situations, there are some everyday uses that can cause memory leaks
  • Mainly include:Context,WebView,Adapter, detailed introduction is as follows

5.6 summarize

Below, I’ll summarize the causes and solutions of memory leaks in Android with a single diagram


6. Memory leak analysis tool

  • Even if you fully understand the cause of a memory leak, it is inevitable that memory leaks will occur
  • The following is a brief introduction to memory leak analysis tools

6.1 Tools

  • Android StudiotheMonitor
  • EclipsetheMAT(Memory Analysis Tools) :www.eclipse.org/mat/
  • YourKit:www.yourkit.com/

Specific use: jiajixin.cn/2015/01/06/…

6.2 Android Open source Libraries

  • LeakCanary(square)
  • BlockCanary

A. Specific introduction: github.com/square/leak… B. specific use: www.liaohuqiu.net/cn/posts/le…


7. To summarize

  • This article introduces the essence, cause and solution of memory leak in a comprehensive way. We hope to avoid memory leak as far as possible when developing

  • In the next article, I’ll be looking at Android performance optimization, so keep an eye on Carson_Ho’s Android development notes


Thumb up, please! Because your encouragement is the biggest motivation for my writing!


Welcome to follow carson_ho’s official wechat account