Detecting and fixing memory leaks in android

Detecting and fixing memory leaks in android
detecting-and-fixing-memory-leaks-in-android

Memory Leaks in Android

This article is all about finding and solving memory leaks in an Android application.

What is a memory leak in android?

Many a time we see ANR dialog while using android apps, lags in our apps, we also see OutOfMemoryError in Android Studio while building apps. All these kinds of stuff happen due to memory leaks.
Some objects are not even recognized by garbage collector as garbage. In these situation you can not do anything.

Help garbage collector, help you.

Holding reference of objects that are not required anymore is a bad practice, freeing objects reference after being served is helpful for the garbage collector to kill that object, that eventually helps yourself in memory leaks issues. If you keep objects reference unnecessarily, it only leads to memory leaks.

Memory leaks can happen easily on an android device if not taken care of while building apps, as android devices are provided with very less memory. Memory leaks are the biggest issue for any android app, in spite of being the biggest issue, it is not much difficult to avoid it, if we give importance while building the app. We need to keep few things in mind while building memory leaks free apps.

Memory leaks can be caused by various ways in android as it is the easiest thing to do.

You can ignore memory leaks but your users can’t.

Reasons memory leak happens.

Most important reason for memory leaks is our own mistakes while building apps. We should avoid some common mistakes while building apps.

What should we avoid to make our app memory leak free?

Holding reference of ui specific object in the background.

Never hold the reference of ui specific object in a background task, as it leads to memory leak.

Using static views

Do not use static views as it is always available, static views never get killed.

Using static context

Never use context as static.

public class MainActivity extends AppCompatActivity {
  
  private static Button button; //NEVER USE LIKE THIS
  private static Context context; //NEVER USE LIKE THIS TOO
  
}

Using Context

Be careful while using context, deciding which context is suitable at places is most important. Use application context if possible and use activity context only if required.

For better understanding about context, refer

Never forget to say goodbye to listeners after being served.

Do not forget to unregister your listeners in onPause / onStop / onDestroy method. By not unregistering, it always keeps the activity alive and keeps waiting for listeners.

Do Like this -

public class LocationListenerActivity extends Activity implements LocationUpdate{

  @Override
  public void onLocationChange(Location location){
    
  }
  
  @Override
  public void onStart(){
   LocationListener.get().register(this);
  }
  
  @Override
  public void onStop(){
   LocationListener.get().unregister(this);
  }

}

Using inner class

If you are using an inner class, use this as static because static class does not need the outer class implicit reference. Using inner class as non static makes the outer class alive so it is better to avoid.
And if you are using views in static class, pass it in the constructor and use it as a weak reference.

Use something like this -

public class MainActivity extends AppCompatActivity {

    TextView textView;
    AsyncTask asyncTask;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.textView);

        asyncTask = new MyBackgroundTask(textView).execute();
    }

    @Override
    protected void onDestroy() {
        asyncTask.cancel(true);
        super.onDestroy();
    }

    private static class MyBackgroundTask extends AsyncTask<Void, Void, String> {

        private final WeakReference<TextView> textViewReference;

        public MyBackgroundTask(TextView textView) {
            this.textViewReference = new WeakReference<>(textView);
        }

        @Override
        protected void onCancelled() {
        }

        @Override
        protected String doInBackground(Void... params) {
            return "some text";
        }

        @Override
        protected void onPostExecute(String result) {
            TextView textView = textViewReference.get();
            if (textView != null) {
                textView.setText(result);
            }
        }
    }
}

Using anonymous class

This is very similar to non static inner classes as it is very helpful but still avoid using an anonymous class.

Using views in collection

Avoid putting views in collections that do not have clear memory pattern. WeakHashMap store views as values. Since WeakHashMap store views as a hard reference it is better to avoid using it.

These all are the reasons leads to memory leaks and then ANR, lags in app and OutOfMemoryError that ultimately leads to uninstallation of your app by users.

Do not blame garbage collector.

If memory leak happens due to these specific reasons, as the garbage collector is not intended to handle these, these are your own mistakes try not to commit these.

How to detect and solve memory leaks issue?

Life was good till we were not introduced with memory leaks.

Though, we got introduced with memory leaks, we only need to find the way how to handles this. So how we are going to detect and fix this. Even detecting and fixing a single bug by own is difficult, so you can imagine how difficult is to find and fix memory leaks for the whole app.

Thanks to “The saviour” LeakCanary for saving us from memory leaks problems, it runs along with the application and helps in detecting where the application is leaking memory. It even notify us about where our app is leaking.