Brief Notes on Android Development: Exploring Android Memory Leaks for App Performance Optimization and Thoroughly Analyzing Source Code

2. Essential reasons

Objects that should have been recycled cannot be recycled for some reason, and thus continue to stay in the heap memory. When an object no longer needs to be reclaimed by GC, but another object in use holds its reference, so it cannot be reclaimed by GC and stays in the heap memory. That is, long-lived objects hold references to short-lived objects, and memory leaks are likely to occur.

Fourth, the main reason for Android memory leaks

(1) Member variables modified by the static keyword

1. Memory leak caused by static modification of context

Description of the problem: static is a keyword in Java. When it is used to modify a member variable, the variable belongs to the class, not an instance of the class. Modifying variables with the static keyword greatly prolongs the life cycle of the variable, and it is extremely convenient to access. It can be directly accessed by using the class name, and it is also extremely convenient to pass values ​​between resources, so it is often used. But if you use it to refer to some resource-consuming instances (Context is the most common case), then you should be cautious.

public class ClassName {

private static Context mContext;

//omit

}

The above code is very dangerous, if the Activity is assigned to mContext. Then even if the Activity has been onDestroy, the Activity will still not be released because there are still objects holding its reference. If there are some resources in the Activity, it will be even worse.

Solution:

1. Try to avoid Static member variables referencing instances that consume too much resources (such as Context).

2. Use weak references WeakReference instead of strong references to hold instances. For example, WeakReference mContextRef can be used.

2. Memory leak caused by singleton

Problem description: Improper use of Android's singleton mode can cause memory leaks. Because of the static nature of the singleton, the life cycle of the singleton is as long as the life cycle of the application. If an object is no longer needed, and the singleton object still holds a reference to the object, the object will not be recycled normally. This leads to a memory leak.

public class BankManager {

private static BankManager instance;

private Context context;

private BankManager(Context context) {

this.context = context;

}

public static BankManager getInstance(Context context) {

if (instance == null) {

instance = new BankManager(context);

}

return instance;

}

}

The above is an ordinary singleton pattern. When creating this singleton, a Context needs to be passed in, so the life cycle of this Context is very important.

  • The Context of the Application is passed in: the life cycle of the singleton is as long as that of the Application, so there will be no problem;

  • The Context of the Activity is passed in: Since the life cycle of the Context is as long as that of the Activity (the Activity inherits indirectly from the Context), the life cycle of the singleton may be longer than the life cycle of the Activity. When the Activity corresponding to this Context exits, its memory will not be reclaimed, because the singleton object holds a reference to the Activity.

Solution:

Context Use Application Context as much as possible, because the life cycle of Application Context is relatively long, and there will be no memory leak problem when referencing it.

The correct singleton should be as follows:

public class BankManager {

private static BankManager instance;

private Context context;

private BankManager(Context context) {

this.context = context.getApplicationContext();

}

public static BankManager getInstance(Context context) {

if (instance != null) {

instance = new BankManager(context);

}

return instance;

}

}

(2) Non-static inner class/anonymous class

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

Description of the problem: In an Activity that starts frequently, in order to avoid repeatedly creating the same data resource, a singleton of a non-static inner class will be created inside the Activity, and the data of the singleton will be used every time the Activity is started. If the life cycle of the instance created by the non-static inner class is equal to the life cycle of the application, the outer class cannot be released because the non-static inner class holds the reference of the outer class, which eventually leads to memory leaks.

public class MainActivity extends AppCompatActivity {

private static TestResource mResource = null;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

if(mManager == null){

mManager = new TestResource();

}

//…

}

private class TestResource {

//…

}

}

The above code creates a single instance of a non-static inner class inside the Activity, and the data of the single instance will be used every time the Activity is started. Although this avoids the repeated creation of resources, it will cause memory leaks. The non-static inner class will hold the reference of the outer class, and use the non-static inner class to create a static instance, which is as long as the life cycle of the application, which causes the static instance to always hold the reference of the Activity, resulting in the failure of the Activity Memory resources cannot be reclaimed.

Solution:

1. Change non-static inner classes to static inner classes (static inner classes do not hold references to outer classes by default)

2. The inner class is extracted and encapsulated into a singleton. If you need to use Context, it is recommended to use Application Context

2. Memory leak caused by Handler

Description of the problem: Memory leaks caused by the use of Handlers should be the most common problem. APIs such as processing network tasks or encapsulating some request callbacks should be handled with the help of Handlers. If the code used for Handlers is not standardized, it may cause memory leaks. For example:

public class MainActivity extends AppCompatActivity {

private Handler mHandler = new Handler() {

@Override

public void handleMessage(Message msg) {

//…doSomething

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

loadData();

}

private void loadData(){

//…request http

Message message = Message.obtain();

mHandler.sendMessage(message);

}

}

This way of creating a Handler will cause a memory leak. Since mHandler is an instance of the non-static anonymous internal class of Handler, it holds a reference to the external class Activity, and the message queue MessageQueue continuously polls and processes messages in a Looper thread. Then when When the Activity exits, there are still unprocessed messages or messages being processed in the message queue, and the Message in the message queue holds a reference to the mHandler instance, and mHandler holds a reference to the Activity, so the memory resources of the Activity cannot be timely Recycled, causing a memory leak.

Solution:

1. Create a static Handler internal class, and then use weak references to the objects held by the Handler, so that the objects held by the Handler can also be recycled during recycling, which avoids Activity leaks.

2. There may still be pending messages in the message queue of the Looper thread, so the messages in the message queue should be removed when the Activity is Destroyed or Stopped.

public class MainActivity extends AppCompatActivity {

private MyHandler mHandler;

private TextView mTextView

If you lack direction on the way to advancement, you can click on my [Github] to join our circle to learn and communicate with Android developers!
Everything below is available on GitHub!

  • A full set of manuals for Android advanced learning

    img

  • Android Benchmark Ali P7 Learning Video

    img

  • BATJ big factory Android high-frequency interview questions

    img

Finally, I end this article with one of my favorite quotes from Jobs:

People can't do too many things in this life, so everything must be done wonderfully.
Your time is limited, so don't live it for others. Don't be limited by dogma, don't live in other people's ideas. Don't let other people's opinions dictate your own inner voice.
Most importantly, be brave enough to follow your heart and intuition. Only your heart and intuition know what you really think, and everything else is secondary.

droid benchmarking Ali P7 learning video

[External link image transfer...(img-M3weIKnP-1645099060747)]

  • BATJ big factory Android high-frequency interview questions

    [External link image transfer...(img-FWtw4Wiq-1645099060747)]

Finally, I end this article with one of my favorite quotes from Jobs:

People can't do too many things in this life, so everything must be done wonderfully.
Your time is limited, so don't live it for others. Don't be limited by dogma, don't live in other people's ideas. Don't let other people's opinions dictate your own inner voice.
Most importantly, be brave enough to follow your heart and intuition. Only your heart and intuition know what you really think, and everything else is secondary.

Guess you like

Origin blog.csdn.net/m0_66264630/article/details/122990786