If you need to reprint the original link, please retain some pictures from Baidu, if there is infringement, please contact to delete

Directory:

  • Three common memory problems
  • A common memory analysis tool for Android development
  • Android memory management mechanism

Introduction (Some status of memory leak problem) :

Memory problems are often hidden, and the Java language used in Android development has its own GC, leading to a lack of attention to memory problems during normal development.

When we do encounter an OutOfMemoryError, the location reported is not necessarily the root cause of the problem. This could just be the straw that breaks the camel’s back.

1. Three common memory problems

1.1 Memory Jitter

Memory jitter: A phenomenon in which a large number of objects are created or reclaimed in a short time.

An intuitive manifestation of memory jitter is the jagged memory usage, as shown in the following figure. This can lead to frequent GC, which can cause the interface to stall.

During the GC process, depending on the GC collector, one or more threads may be allocated to GC, and other worker threads may need to be suspended, which can affect UI drawing and lead to stalling.

Why does GC need to stop other threads?

The main purpose is to prevent other threads from accessing an object and changing its state during the garbage collector inspection. Because at the very beginning of garbage collection, all objects in the current managed heap are iterated and marked, with references marked as 1 and none marked as 0, and those marked as 0 are the objects that the GC needs to collect.

1.2 Memory Leaks

A memory leak is when some of our objects are not properly reclaimed, resulting in a gradual decrease in available memory. As the available memory becomes smaller and smaller, it is easy to trigger memory overflow.

Why are some objects not recycled correctly?

When an object with a long declaration period holds a reference to an object with a short lifetime, the object with a short lifetime cannot be collected by the garbage collection mechanism.

Common Memory leaks in Android:

1.2.1 Memory Leakage Caused by singleton

In Android development, the life cycle of a singleton follows the life cycle of the entire app. If there is a Fragment or Activity context in it, it will be unable to be released.

public class Utils {
    private Context mContext;
    private static volatile Utils mUtils;
    
    private Utils(Context context){
        this.mContext = context;
    }
    
    public static Utils getInstance(Context context){
        if(mUtils == null) {synchronized(Utils.class) {
                if(mUtils == null){
                    utils = new Utils(context);
                    // Resolve: you can use aplicationContext as its variable
                    //utils = new Utils(context.getApplicationContext());}}}returnmUtils; }}Copy the code
1.2.2 Memory leaks caused by non-static inner classes

It can be roughly divided into two situations:

1. Memory leaks caused by static instances created by non-static inner classes

The reason for this is similar to the singleton above:

  • Non-static inner classes hold references to external classes by default.
  • A static instance is created using this non-static inner class. The lifetime of the static instance is as long as that of the application. As a result, the static instance will always hold a reference to the Activity, causing the Activity’s memory resources to fail to be recycled properly.
public class MainActivity extend AppCompatActivity{
    // To avoid frequent initialization, declare test as a static variable
    private static Test test;
    
    @Overide
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
    }
    
    private void initData(a){
        if(test == null){
            test = newTest(); }}// Non-static inner class Test
    private class Test{}}Copy the code

2. Memory leaks due to uncontrollable thread life cycles in inner classes

For example, handler and AsyncTask are commonly used. The reason:

  • A non-static anonymous inner class has an implicit reference to its outer class.
  • If the asynchronous task of the non-static inner class is not completed before the destruction of its external class, the memory resources of the external class cannot be released normally, resulting in a memory leak.

HandlerActivity
Handler
Handler
HandlerActivity
HandlerActivity
HandlerActivity
If the delayed task is completed after five minutes, the activity will reclaim, so the leak is temporary.

Solution:

  • With static inner classes, static inner classes do not hold references to external classes. If you want to use an external class, you can save a reference to an external class as a soft or weak reference. Static classes don’t hold objects from external classes, so your Activity can be reclaimed at will. Since the Handler no longer holds references to external class objects, the application will no longer allow you to manipulate objects in your Activity in the Handler. So you need to add a WeakReference to the Activity in the Handler.

  • Program logic can also be used to protect against uncontrolled internal class thread life cycles

    1. Stop your background thread while closing the Activity. When the thread stops, the Activity is automatically reclaimed at the appropriate time.
    2. If your Handler is referenced by delay’s Message, remove the Message object from the Message queue using the corresponding Handler’s removeCallbacks() method.
1.2.3 listener

We often get system services through context.getSystemService (). These services usually help us with some background tasks or interactions with hardware in their own processes. When we register these listeners, they hold references to the Context and can cause memory leaks if they are not unregistered.

void registerListener(a) {
       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 void onClick(View v) { registerListener(); nextActivity(); }});Copy the code
1. Other

If your code uses the C layer memory area, you need to handle it manually. The Java GC will not free the memory for you.

Eg. Before Android 3.0(API level 11), Bitmap pixel data and Bitmap objects are stored separately, pixel data is stored in native Memory, and objects are stored in Dalvik heap.

This Bitmap object is allocated by the Java part, when not used, the system will automatically reclaim, but the corresponding C available memory area, virtual machine is not directly reclaimed, this can only call the underlying function release. So you need to call the recycle() method to free up memory in part C. More on bitmap memory issues will be covered separately in a later article.

Do open files (streams) cause memory leaks?

We often see various online sources that open files, not closed will lead to memory leaks, in fact, this statement is not accurate.

  1. When we do this FileInputStream(“/hello.txt”) gets a file descriptor.
  2. Each process has a limit on the file descriptors available. Therefore, if file Descriptor is not released, subsequent actions (socket connection, read/write files, etc.) that depend on file Descriptor cannot be implemented.
  3. When we call FileInputStream.close, it frees the file descriptor.

Therefore, when we use the stream normally, there is no memory leak. Not closing streams is not a memory leak, it is a resource leak.

Reference: www.reddit.com/r/learnjava…

Droidyue.com/blog/2019/0…

1.3 Memory Overflow

Out Of Memory is the OOM (Out Of Memory). The amount of memory currently occupied plus the amount of memory we have requested exceeds what the Java virtual machine can allocate. This problem can occur when memory leaks are severe, or when a large amount of memory is suddenly required.

2 Common memory analysis tools

2.1 the Memory Profiler

Android Is a tool that comes with Android Studio and uses real-time charts to show memory usage.

Function:

  • You can intuitively observe the memory usage and determine whether memory leaks or jitter occur
  • Heap dump, force GC, track memory allocation

View
Tool Windows
Profiler

Click + to select the application to listen on.

For details, please refer to Google’s official documentation:

Use Memory Profiler to view Java heap and Memory allocation

Cannot access to view this article translation: www.jianshu.com/p/20a2e7dad…

2.2 LeakCanary

Square is a lightweight third-party memory leak detection tool github.com/square/leak… Main principles:

  1. Listen for the Activity’s life cycle
  2. On onDestroy, create the Reference and ReferenceQueue and start the background process to detect it
  3. After a period of time, it reads from the ReferenceQueue. If the Reference of the corresponding activity cannot be read, there may be leakage. At this time, it triggers GC again, and after a period of time, it reads again. If the Reference of the corresponding activity cannot be read from the ReferenceQueue, it can be concluded that there is a memory leak
  4. After a memory leak occurs, debug. dump analyzes the hprof file to find the leak path.

2.3 Memery Analyzer Tool (MAT)

It started out as an Eclipse plug-in. There is also a standalone version now. Download address: www.eclipse.org/mat/downloa… I’m using Windows 64-bit version 1.9.1, zip package 66.8 MB

  • Powerful Java Heap analysis tool that can be used to find memory leaks and footprint
  • Generate overall reports, analyze problems, etc

3. Android memory management mechanism

Before looking at the short section, it is best to have a general understanding of Java memory management and GC by taking a look at Java’s GC mechanism and memory mechanism

3.1 Android memory allocation is elastic

  • The assigned value and maximum value depend on the device. You don’t allocate too much at first, you redistribute when you don’t have enough, and the size of the new allocation is not random, it’s finite. Get memory allocated by App
    ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    // Maximum memory allocation
    int memory = activityManager.getMemoryClass();
    System.out.println("memory: "+memory);
    // Maximum memory allocation method 2
    float maxMemory = (float) (Runtime.getRuntime().maxMemory() * 1.0/ (1024 * 1024));
    // Total memory currently allocated
    float totalMemory = (float) (Runtime.getRuntime().totalMemory() * 1.0/ (1024 * 1024));
    // Free memory
    float freeMemory = (float) (Runtime.getRuntime().freeMemory() * 1.0/ (1024 * 1024));
    System.out.println("maxMemory: "+maxMemory);
    System.out.println("totalMemory: "+totalMemory);
    System.out.println("freeMemory: "+freeMemory); HTTPS://blog.csdn.net/wolfking0608/article/details/83185943
Copy the code

Android :largeHeap=”true” will request the VM to allocate more memory for the App, but not as much memory as the system has. Instead, it is limited by dalvik.vm. Heapsize, usually written in /system/build.prop:

dalvik.vm.heapsize=128m  
dalvik.vm.heapgrowthlimit=64m  

<application
     .
     android:label="XXXXXXXXXX"
     android:largeHeap="true">.</application>
Copy the code

3.2 Low Memory Killer Mechanism

Process priority: A process with a lower priority has a higher probability of being killed.

  1. Foreground processes: normally will not be killed
  2. Visible processes: Normally will not be killed
  3. Server process: Normally it will not be killed
  4. Background processes: Stored in an LRU cache list, the process at the end of the list is killed first
  5. Empty processes: Normally, Android does not save these processes

Reclaim revenue: When the Android system starts to kill processes in the LRU cache, the system determines the reclaim revenue generated by each process killed. Because The Android system tends to kill a process that can reclaim more memory, it can kill fewer processes to gain more memory. The fewer processes you kill, the less impact it has on the user experience.

3.3 Differences between Dalvik VM and Art in memory reclamation:

  • Dalvik has a fixed garbage collection algorithm

  • The Art recovery algorithm can be selected according to specific scenarios. For example, the task is in the foreground and the corresponding speed is the most important. A simple mark-clear algorithm can be selected. For background applications, the mark-collation algorithm is optional.

4. Conclusion

The next article will focus on Bitmaps and the memory problems in bitmaps.

Eight Ways Your Android App Can Leak Memory github.com/francistao/…