SoFunction
Updated on 2025-03-11

5 common memory leak problems and solutions in Android development

An object in Android is no longer needed, but other objects still hold their references, which makes it unable to recycle, causing the object to be temporarily stored in memory, so that memory leaks occur.

If there are too many memory leaks, it will cause the application to occupy too much memory. When the memory occupied exceeds the memory allocated by the system, memory overflow will occur and cause the application to Crash.

After understanding the causes and impacts of memory leaks, what we need to do is to master common memory leaks and try to avoid them in future Android program development. Below are 5 common memory leak problems and solutions in Android development. Share them with you and let’s take a look.

one,Memory leak caused by singletons

Everyone likes to use the single column of Android. However, the static characteristics of the singleton pattern make its life cycle as long as the application life cycle, which means that an object does not need to be used and the singleton object still holds an object, so the object cannot be released, which will cause memory leakage.

Example:

public class AppManager {
 private static AppManager instance;
 private Context context;
 private AppManager(Context context) {
  = context;
 }
 public static AppManager getInstance(Context context) {
 if (instance != null) {
 instance = new AppManager(context);
 }
 return instance;
 }
}

This singleton needs to pass in the Context object, so the length of the life cycle of this Context is crucial:

1. The Context of Application is passed in: this will have no problem because the life cycle of a singleton is as long as that of Application;

2. The activity's Context is passed in: When the Activity corresponding to this Context exits, since the life cycle of the Context is as long as the Activity (the Activity is indirectly inherited from the Context), its memory will not be recycled when the Activity exits, because the singleton object holds a reference to the Activity.

Therefore, the correct singleton should be modified to the following method:

public class AppManager {
 private static AppManager instance;
 private Context context;
 private AppManager(Context context) {
  = ();
 }
 public static AppManager getInstance(Context context) {
 if (instance != null) {
 instance = new AppManager(context);
 }
 return instance;
 }
}

This way, no matter what Context is passed in, the Application's Context will eventually be used, and the singleton's life cycle is as long as the application's, thus preventing memory leaks.

2. Memory leak caused by creating static instances of non-static internal classes

Sometimes we may start activities frequently. In order to avoid repeatedly creating the same data resources, this way of writing occurs:

public class MainActivity extends AppCompatActivity {
 private static TestResource mResource = null;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 (savedInstanceState);
 setContentView(.activity_main);
 if(mManager == null){
 mManager = new TestResource();
 }
 //...
 }
 class TestResource {
 //...
 }
}

This creates a singleton of a non-static inner class inside the Activity, and the data of the singleton is used every time the Activity is started. Although the duplicate creation of resources is avoided, this writing will cause memory leaks, because the non-static inner class will hold references to the external class by default, and the non-static inner class will create a static instance. The life cycle of the instance is as long as the application, which causes the static instance to always hold references to the Activity, resulting in the Activity's memory resources that cannot be recycled normally. The correct way to do it is:

Set the inner class as a static inner class or extract the inner class and encapsulate it into a singleton. If you need to use Context, please use ApplicationContext.

3. Memory leak caused by Handler

The memory leak problem caused by the use of Handler should be said to be the most common. When handling network tasks or encapsulating some request callbacks, they should use Handler to handle it. If the code of Handler is not standardized, it may cause memory leaks, as shown in the following example:

public class MainActivity extends AppCompatActivity {
 private Handler mHandler = new Handler() {
 @Override
 public void handleMessage(Message msg) {
 //...
 }
 };
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 (savedInstanceState);
 setContentView(.activity_main);
 loadData();
 }
 private void loadData(){
 //...request
 Message message = ();
 (message);
 }
} 
 

This way of creating a Handler will cause memory leaks. Since mHandler is an instance of the non-static anonymous internal class of the Handler, it holds a reference to the external class Activity. We know that the message queue is constantly polling and processing messages in a Looper thread. When this Activity exits, there are still unprocessed messages in the message queue or are processing messages. The Message in the message queue holds a reference to the mHandler instance, and mHandler holds a reference to the Activity, which causes the memory resources of the Activity to be unable to be recycled in time, causing a memory leak. Therefore, another method is:

public class MainActivity extends AppCompatActivity {
 private MyHandler mHandler = new MyHandler(this);
 private TextView mTextView ;
 private static class MyHandler extends Handler {
 private WeakReference<Context> reference;
 public MyHandler(Context context) {
 reference = new WeakReference<>(context);
 }
 @Override
 public void handleMessage(Message msg) {
 MainActivity activity = (MainActivity) ();
 if(activity != null){
 ("");
 }
 }
 }
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 (savedInstanceState);
 setContentView(.activity_main);
 mTextView = (TextView)findViewById();
 loadData();
 }
 private void loadData() {
 //...request
 Message message = ();
 (message);
 }
}

Create a static Handler inner class and use weak references to the objects held by the Handler. In this way, objects held by the Handler can also be recycled during recycling. Although the activity leakage is avoided, there may still be pending messages in the message queue of the Looper thread. Therefore, we should remove the messages in the message queue when Destroy or Stop of the Activity. The more accurate approach is as follows:

public class MainActivity extends AppCompatActivity {
 private MyHandler mHandler = new MyHandler(this);
 private TextView mTextView ;
 private static class MyHandler extends Handler {
 private WeakReference<Context> reference;
 public MyHandler(Context context) {
 reference = new WeakReference<>(context);
 }
 @Override
 public void handleMessage(Message msg) {
 MainActivity activity = (MainActivity) ();
 if(activity != null){
 ("");
 }
 }
 }
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 (savedInstanceState);
 setContentView(.activity_main);
 mTextView = (TextView)findViewById();
 loadData();
 }
 private void loadData() {
 //...request
 Message message = ();
 (message);
 }
 @Override
 protected void onDestroy() {
 ();
 (null);
 }
}

Use (null); is to remove all messages and all Runnables in the message queue. Of course, you can also use(); or(); to remove the specified Runnable and Message.

4. Memory leak caused by unclosed resources

For the use of resources such as BraodcastReceiver, ContentObserver, File, Cursor, Stream, Bitmap, etc., it should be closed or cancelled in time when the Activity is destroyed, otherwise these resources will not be recycled, causing memory leakage.

5. Memory leak caused by threads

Memory leaks caused by threads are also common. Everyone may have written the following two examples:

//——————test1
 new AsyncTask<Void, Void, Void>() {
 @Override
 protected Void doInBackground(Void... params) {
 (10000);
 return null;
 }
 }.execute();
//——————test2
 new Thread(new Runnable() {
 @Override
 public void run() {
 (10000);
 }
 }).start(); 

The asynchronous tasks and Runnable above are both an anonymous inner class, so they all have an implicit reference to the current Activity. If the task is not completed before the Activity is destroyed, the memory resources of the Activity will be unable to be recycled, causing memory leaks. The correct way is to use static inner classes, as follows:

static class MyAsyncTask extends AsyncTask<Void, Void, Void> {
 private WeakReference<Context> weakReference;
 public MyAsyncTask(Context context) {
  weakReference = new WeakReference<>(context);
 }
 @Override
 protected Void doInBackground(Void... params) {
  (10000);
  return null;
 }
 @Override
 protected void onPostExecute(Void aVoid) {
  (aVoid);
  MainActivity activity = (MainActivity) ();
  if (activity != null) {
  //...
  }
 }
 }
 static class MyRunnable implements Runnable{
 @Override
 public void run() {
  (10000);
 }
 }
//——————
 new Thread(new MyRunnable()).start();
 new MyAsyncTask(this).execute(); 

This avoids the leakage of memory resources in the Activity. Of course, when the Activity is destroyed, the corresponding task should also be cancelled to avoid wasting resources when the task is executed in the background.

The above are the five common memory leak problems and corresponding solutions in Android programming. If you encounter the above leak problems during programming, you might as well try the corresponding methods.

The above is all the content of this article. I hope that the content of this article will help you study or work. I also hope to support me more!