Memory leak of Android memory notes

Memory leak of Android memory notes

1. What is a memory leak?

1. Memory recovery

The characteristics of Java allow us not to apply for memory through malloc, nor to actively release it. Java will help us reclaim memory that is no longer used. This process is called GC.

How does the virtual machine know which objects should be recycled and which objects should be recycled? The virtual machine adopts a reachability policy.

The virtual machine defines a series of GC Roots. If an object is reachable from the GC Root , it will not be recycled. If this object is not reachable from any GC Root, the virtual machine will consider it an object that is no longer used and recycle it.
insert image description here

As shown in the figure, both a and b are recyclable objects.

2. What are GC Roots?

  • Objects referenced in the virtual machine stack (local variable table in the stack frame)
  • The object referenced by JNI (generally speaking, Native method) in the local method stack
  • Objects referenced by class static properties in the method area
  • Objects referenced by constants in the method area

For specific explanation, please refer to https://blog.csdn.net/weixin_38007185/article/details/108093716.

3. Memory leak

Here is a more graphic analogy:

There is a very popular restaurant with limited seating. The restaurant sent someone to patrol. When there were not enough seats, they patrolled to see if anyone was still lingering after eating, and drove them away to give up their seats to customers who were still in line. (This process is GC). But if someone finishes eating and the patrol doesn't chase them away, the slot is wasted.

The restaurant is the equipment, the seat is the memory, and the customer is the object. When the object is no longer used, but still occupies the memory and does not release it, making this memory unavailable , this phenomenon is called a memory leak.

4. Why is there a memory leak?

Through the GC recycling strategy, we can know that deciding whether an object is recycled is based on whether it is reachable from the GC Root. The leaked object is directly or indirectly referenced by GC Root, causing the virtual machine to think that it is still in use, so it will not be recycled.

2. Common Activity memory leaks

1. Handler causes Activity to leak

Cause of leakage

You must have seen in various places that the anonymous inner class Handler is easy to cause Activity leaks, because the anonymous inner class holds a reference to the outer class.

But this statement is easy to cause misunderstanding: think that anonymous inner classes will cause memory leaks. This statement is not comprehensive.

If it causes a leak, it must be recycled but not recycled, so it is necessary to analyze why the Activity cannot be recycled here.

The common scenario where Handler will cause Activity leakage is that the Message sent by Handler is still in MessageQueue, that is, the message has not been executed yet.

At this time, the MessageQueue holds this Message, and through the analysis of the source code of Handler's sendMesesage, we can know that it finally came to the method of enqueueMessage()

	private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
    
    
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
    
    
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

Through msg.target = this, we can know that this Message holds a Handler. As an anonymous inner class, Handler holds Activity, so a chain of references like this is generated:

Main thread —> threadlocal —> Looper —> MessageQueue —> Message —> Handler —> Activity

The threadlocal here will not be recycled by gc, so the activity cannot be recycled, which leads to the leak.

Solution

There are two solutions:

  1. Define the handler as a static anonymous inner class, and then hold the Activity as a weak reference.
  2. When the Activity is destroyed, clear the Message sent by the Handler.

2. Memory leak caused by static class holding Activity or Context

Cause of leakage

Because the life cycle of the static class is as long as the application cycle, if the static class directly or indirectly holds a reference to the Activity, it will also cause a memory leak.

2.1 Singleton mode

The implementation of the singleton mode is basically static, so the life cycle is as long as the application cycle.

2.2 Static instances of non-static inner classes

Seeing the name is a bit confusing, in fact, it is probably the following situation:

public class TTestAActivity extends AppCompatActivity{
    
    

     private static Handler mHandler = null;


     @Override
     protected void onCreate(@Nullable Bundle savedInstanceState) {
    
    
          super.onCreate(savedInstanceState);
          mHandler = new Handler(Looper.getMainLooper()) {
    
    
               @Override
               public void handleMessage(@NonNull Message msg) {
    
    
                    super.handleMessage(msg);
               }
          };
     }
}

At this time, the handler holds a reference to the external class as an anonymous internal class, but it is a static variable, which will cause the Activity to leak.

Solution

Don't let the static class hold some data for a long time, and empty it in time when it is not in use. Also don't use static instances of non-static inner classes.

3. The memory leak caused by the unregistered broadcast receiver

Cause of leakage

When learning the use of broadcasting, I saw that it was emphasized many times that the broadcast receiver was registered, and unregisterReceiver() needs to be performed when it is destroyed. The registered broadcast receiver will have such a reference chain:

Application -> LoadApk -> BroadcastReceiver

At this time, if unregisterReceiver() is not timely, it will cause the broadcast receiver to leak. If the BroadcastReceiver is still an internal class in the Activity, then he holds the Activity, which in turn will cause the Activity to leak.

Solution

Log out in time for broadcasts that are not within the scope of use.

4. Resource usage is not closed

Cause of leakage

The resources here include file stream InputStream, OutputSteam, file File, database cursor Cursor, image Bitmap. If these resources are not closed in time, the system will not recycle them, which will lead to Activity leakage.

Solution

// 对于 文件流File:关闭流
InputStream / OutputStream.close()
// 关闭文件
file.close()
// 关闭游标
cursor.close()
// 回收bitmap占用的内存
bitmap.recycle()
bitmap = null

3. Summary

For the analysis of the leakage problem, we must grasp the key points, that is, what should be recycled is not recycled, and if it is not recycled, it must start from the reference chain that should not exist from GCRoot.

Grasping this key point, the analysis of the memory leak problem is mainly to find out this unreasonable reference chain.

Guess you like

Origin blog.csdn.net/qq_43478882/article/details/129228130