Suggest collect, otherwise can’t find!!

preface

Memory leaks are common on Android; This article comprehensively introduces the nature, causes and solutions of memory leaks, and finally provides some common memory leak analysis tools. I hope you will like them.

directory

1. Introduction

Memory Leak refers to a situation in which a program allocates Memory that is no longer needed but cannot be released & returned to the program

2. Impact on applications

The application is prone to memory overflow, that is, OOM memory overflow

3. The root cause of memory leakage

A detailed description

  • Note in particular that from a mechanical point of view, there should be no memory leaks due to Java’s garbage collection (GC) mechanism; A memory leak occurs simply because an external human cause = unconsciously holds object references, making the life cycle of the holder of the reference > the life cycle of the referenced

4. Knowledge: Android memory management mechanism

4.1 introduction

In the following sections, we will go into details about memory allocation & reclamation for recycling processes, objects, and variables

4.2 Memory Policy for Processs. a. Memory Allocation Policy ActivityManagerService centrally manages memory allocation for all processs. b. Step 1: The Application Framework determines the process type to be reclaimed. When the process space is limited, it automatically reclaims processes in the order of low ->> high priority. Android divides processes into five priority levels as follows:

ActivityManagerService scores all processes (the scores are stored in variable ADJ) and updates the scores to the Linux kernel. The Linux kernel does the actual memory reclamation

Here only summarizes the process, the process of the complex, interested readers can research system source ActivityManagerService. Java

4.2 Memory Policies for Objects and variables

  • Android has the same memory policy for objects and variables as Java
  • Memory management = memory allocation of objects/variables + memory release

Next, we will explain memory allocation & memory release policy in detail a. Memory allocation policy

  • The memory allocation of objects/variables is taken care of automatically by the program
  • There are three types of allocation: static allocation, stack allocation, & heap allocation, respectively for static variables, local variables & object instances detailed introduction as follows

Note: Use an example to explain memory allocation

public class Sample { int s1 = 0; Sample mSample1 = new Sample(); Public void s1, mSample1 public void s1, mSample2 public void s1, mSample1 public void s1, mSample2method() { int s2 = 0; Sample mSample2 = new Sample(); MSample3 = new Sample(); mSample3 = new Sample();Copy the code

B. Memory release policy

  • The memory freeing of objects/variables is handled by the Java Garbage Collector (GC)/frame stack
  • The focus here is on the memory free strategy for 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, onto the stack, relatively simple, so it is not described in detail

  • Java Garbage Collector (GC) memory free = garbage collection algorithm, including:

The details are as follows

5. Common Causes of memory leaks & Solutions

Common causes of memory leaks are as follows:

  1. Collection classes
  2. The Static keyword modifies a member variable
  3. Non-static inner class/anonymous class
  4. The resource object is not closed after use

Below, I’ll detail each of the causes of a memory leak

5.1 collection class

  • The collection element object cannot be reclaimed after the collection element object is added to the collection class. This causes a memory leak.
List List<Object> objectList = new ArrayList<>();for(int i = 0; i < 10; i++) { Object o = new Object(); objectList.add(o); o = null; } // The collection element reference itself is freed: o=null) // But the collection List still refers to the object, so the garbage collector still cannot collect the objectCopy the code
  • After a 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 & set to NULL

// Release objectList objectlist.clear (); objectList=null;Copy the code

5.2 Member variables modified by the Static keyword

  • The lifetime of a member variable decorated with the Static keyword = the lifetime of the application
  • If a member variable modified by the Static keyword refers to an instance (such as Context) that consumes too many resources, the life cycle of the member variable is likely to be higher than the life cycle of the reference instance. When the reference instance needs to be destroyed at the end of its life cycle, it cannot be recycled because the Static variable is held. Thus, memory leaks occur.
Public class class name {// Define a static variable private static Context mContext; / /... // Reference the Activity's context mContext = context; // When an Activity needs to be destroyed, the Activity cannot be reclaimed because mContext = static & lifecycle = the life cycle of the application, resulting in a memory leak.Copy the code
  • The solution
  1. Try to avoid Static member variables referencing resource-intensive instances (such as Context)

If Context is referenced, use Applicaiton’s Context as much as possible

  1. WeakReference is used instead of strong reference to hold instances

Note: A very typical example of a static member variable is the singleton pattern

  • Because of its static nature, the lifetime length of the stored knowledge singleton pattern is equal to the lifetime of the application
  • Leak cause If an object is no longer needed and a singleton still holds a reference to that object, the object cannot be recycled properly, resulting in a memory leak

Example demonstration:

// Since the singleton holds a reference to the Activity (until the end of the application lifecycle), even if the Activity exits, The Activity's memory is not 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) {public SingleInstanceClass getInstance(context context) {if (instance == null) {
            instance = new SingleInstanceClass(context);
        }        
        returninstance; }}Copy the code
  • The lifecycle of the object referenced by the solution singleton pattern = the lifecycle of the application

In the example above, the Application Context should be passed, since 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/anonymous classes hold references to external classes by default; Static inner classes do not
  • Instance of a non-static inner class = static, multithreaded, message passing mechanism (Handler)

5.3.1 Instances of non-static inner classes = static

  • If the instance created by a non-static internal class is static (its life cycle is equal to the life cycle of the application), the external class cannot be released because the non-static internal class has references to the external class by default, resulting in memory leakage

An example of a static object holding a non-static inner class in an external class:

// Background: a. When an Activity is started frequently, a singleton of a non-static inner class is created 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: Set it to static 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 {//... The innerClass life of a singleton of a non-static innerClass = the life of the App that holds a reference to the external class TestActivity // b. TestActivity cannot be collected by GC, resulting in a memory leakCopy the code
  • The solution
  1. Set non-static inner classes to: static inner classes (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 that = static

To use Context, you are advised to use the Application Context

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

  • Multithreading = non-static inner class/anonymous class; That is, the thread class is a non-static inner class/anonymous class
  • When a worker thread is working on a task & an external class needs to be destroyed, the worker thread instance holds a reference to the external class, making it impossible for the external class to be collected by the garbage collector (GC), resulting in a memory leak

Multithreading mainly uses: AsyncTask, implementing Runnable interface and inheriting Thread class memory leakage principle of the first three is the same, the inheritance of Thread class as an example

Examples demonstrate

Public class MainActivity extends appactivity {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 void Overriderun() {
                try {
                    Thread.sleep(5000);
                    Log.d(TAG, "Performed multithreading."); } catch (InterruptedException e) { e.printStackTrace(); }}}} /** * Mode 2: anonymous Thread internal 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 multithreaded new through anonymous inner classesThread() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    Log.d(TAG, "Performed multithreading."); } catch (InterruptedException e) { e.printStackTrace(); } } }.start(); }} /** * */ / The Thread class belongs to a non-static inner class/anonymous inner class. The runtime holds references to external classes by default. Will make external classes unable to be collected by the garbage collector (GC), resulting in a memory leakCopy the code
  • As you can see from the above, there are two key conditions that can cause memory leaks:
  1. A worker thread instance holds a reference to an external class
  2. Life cycle of the worker thread instance > life cycle of the external class, i.e. the worker thread is still running and the external class needs to destroy the solution = make any of the above conditions not true.
// There are two solutions: static inner class & force the thread to terminate when the outer class terminates // 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. Make Thread subclasses static inner classes */ 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(); } // Analysis 1: Custom Thread subclass // Set to: private static class MyThread extends Thread{@override public voidrun() {
                try {
                    Thread.sleep(5000);
                    Log.d(TAG, "Performed multithreading."); } catch (InterruptedException e) { e.printStackTrace(); }}}} /** * Solution 2: Force thread termination when an external class terminates its life cycle * Principle: Synchronize the life cycle of a worker thread instance with the life cycle of an external class * Implementation: Force the thread to terminate (stop ()) */ @override protected void when the external class (in this case, the Activity) ends its life cycle (onDestroy () is called)onDestroy() { super.onDestroy(); Thread.stop(); // Force the thread to terminate at the end of the Activity life cycle}Copy the code

5.3.3 messaging mechanism: HandlerAndroid memory leaks: explanation Handler leak reason and solution for https://www.jianshu.com/p/031515d8a7ca

5.4 The Resource Object is Not Closed After Being Used

  • If resources (such as broadcast BraodcastReceiver, File stream File, database Cursor, and image resource Bitmap) are not closed or unregistered when the Activity is destroyed, they will not be reclaimed, resulting in memory leakage
  • The solution closes/unlogs the resource when the Activity is destroyed
// For broadcast BraodcastReceiver: unregisterReceiver() // For File stream File: InputStream/outputstream.close () // For database cursor: close cursor after use // For image resource Bitmap: Android allocates only 8M memory for images. If a Bitmap takes up a lot of memory, it calls recycle() to reclaim the memory occupied by pixels of this object when it is no longer in use. Finally, assign to null bitmap.recycle (); Bitmap = null; // For animation (property animation) // Set animation to repeatCount = "infinite" after // Remember to stop animation when Activity exitsCopy the code

5.5 Other Uses

  • In addition to the four common situations mentioned above, there are some everyday uses that can cause memory leaks
  • Context, WebView, and Adapter are described as follows

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

6. Tools to help analyze memory leaks

  • Even if the cause of memory leaks is fully understood, memory leaks will inevitably occur
  • The following will briefly introduce several mainstream tools for analyzing memory leaks, respectively
  1. MAT(Memory Analysis Tools)
  2. Heap Viewer
  3. Allocation Tracker
  4. Memory Monitor for Android Studio
  5. LeakCanary

6.1 MAT (Memory Analysis Tools)

  • Definition: an Eclipse Java Heap analysis tool ->> download address
  • Function: View the current memory usage

By analyzing the Memory snapshot HPROF analysis of a Java process, you can quickly calculate the size of objects in memory and see which objects cannot be collected by the garbage collector & visually view the objects that might cause this result

Specific usage: MAT usage guide

6.2 Heap Viewer

Definition: a Java Heap memory analysis tool to view a snapshot of the current memory

You can view the proportion of each type of data in the total heap memory

Specific usage: Heap Viewer usage guide

6.3 Allocation Tracker

Description: This tool is used to track memory Allocation information and arrange memory Allocation information in sequence

6.4 the Memory Monitor

Android Studio is a graphical memory detection tool that tracks system/application memory usage. The core functions are as follows

Specific usage: Android Studio Memory Monitor usage guide

6.5 LeakCanary

Synopsis: a square of the Android open source library – > > download address: memory leak detection of specific use: www.liaohuqiu.net/cn/posts/le…

7. To summarize

This article comprehensively introduces the nature, causes and solutions of memory leaks. We hope that you can avoid memory leaks when developing

The article is not easy, if you like this article, or help you hope that you like to forward attention oh. The article will be updated continuously. Absolutely dry!!