Open In App

Top 10 Android Memory Leak Causes

Last Updated : 29 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Memory leak is one of the major issues that annoy all developers frequently. In mobile applications like Android, we have very limited memory, unlike system applications. In Android development, memory leaks are a pervasive challenge(sometimes they result in application crashes which is a very bad user experience), so developers need to consider them while developing otherwise it can affect the performance and stability of applications. A Garbage collector determines the piece of memory that’s not being used anymore by the program and it makes that memory free back to the heap, this process is called garbage collection.

Android Memory Leak Causes

Sometimes applications retain references to these objects that are no longer in use, it actually prevents garbage collectors from releasing the memory which results in memory leaks. Today in the article we will talk about 10 causes that can lead to memory leak in Android Applications along with examples and the ways that can help developers prevent these memory leaks so applications can run long without memory leaks which ultimately will give the best experience to end users.

Top 10 Android Memory Leak Causes

Let’s have a look into the top 10 reasons that can cause Memory Leaks in Android applications.

1. Static References Across the Applications

Holding references to the object or activities using static variables results in memory leaks because static references persist in memory throughout the lifecycle of the application.

Let us understand this by looking at the example:

Java




public class MySingletonClass {
    private static MainActivity mainActivity;
}


In this example, reference to the static variable main activity will persist in memory throughout the application lifecycle.

Prevention:

The use of WeakReference to hold the Reference of Activities or other objects and release them when not needed can help Android developers to prevent memory leaks that can occur due to static references.

Lets loot examples of how we can use WeakReference to prevent memory leaks due to static references.

Java




public class MySingletonClass {
    private static WeakReference<MainActivity> mActivityReference;
  
    public static void setActivity(MainActivity activity) {
        mActivityReference = new WeakReference<>(activity);
    }
  
    public static MainActivity getActivity() {
        return mActivityReference.get();
    }
}


2. Long Live(unused) Callbacks

Callbacks are core or very frequently used code features by developers. While developing developers frequently came across the situations where they need register callbacks. Skipping un-registering those callbacks can lead to memory leaks.

Let’s look at an example of how developers register callbacks in applications.

Kotlin




Class MainActivity : AppCompatActivity() {
    private val sm: SensorManager by lazy {
        getSystemService(Context.SENSOR_SERVICE) as SensorManager
    }
    private val sensorEventListener = object : SensorEventListener {
        // This method will get called each time device receive sensor activity
    }
 override fun onResume() {
        super.onResume()
        val accelerometerSensor = sm.getDefaultSensor(Sensor.TYPE_GRAVITY)
        sm.registerListener(sensorEventListener, accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL)
    }
   }


In above code sensorEventListener will receive events even user place application in background which is not needed.

Prevention:

Removing callback listeners when events are not needed can help developers to prevent unnecessary call back events which will not cause memory leaks. Let’s take an example by unregistered the sensor that we have registered in the above code snippet.

Write below line in Activity’s pause/destroy method.

Kotlin




sm.unregisterListener(sensorEventListener) // This will Unregister the listener to avoid unnecessary callbacks


3. Large Bitmap and Image loading

Bitmap and Images are an essential part of Application development. If we talk about Android applications specifically, mostly each screen contains Images/Bitmaps. Sometimes developers hold reference to bitmaps even if not needed which causes the memory leak(mostly known as out of memory error). Using large size images also sometimes takes a lot of memory and causes the memory leak.

Example:

Kotlin




val bitmap = BitmapFactory.decodeResource(resources, File(“ImagePath”))


Prevention:

Calling recycle() method on bitmap when there is no more usage of Bitmap, Using third party libraries like Glide, Picasso can help to load or render image in a better way that can help to prevent memory leaks.

4. Holding Context Reference

In activity, fragments, service or any utility class developers need use of context very often. For instance, to display Toast we need to pass context as parameter, to get string from resources we need context etc. Developers define references to those contexts and use them in classes or pass them as parameters. Context are very large objects since they come up with plenty of utility methods. Holding those references for a long time or unnecessarily results in memory leaks.

Kotlin




fun main(args: Array<String>) {
    println("GeeksforGeeks")
}


Prevention:

Using Application context or using WeakReference to hold context objects can help to reduce memory leaks. Consider below code how we can use application context.

Kotlin




fun main(args: Array<String>) {
    println("GeeksforGeeks")
}


5. Event Listeners and Broadcast Receivers

Broadcast receivers are one kind of service that remains active even if activity or components are already destroyed. Developers need to follow best practices while using Broadcast Receivers. So registering those broadcasts without un-registering them on Activity destroy can cause memory leaks in applications.

Let’s consider registering a broadcast receiver in Activity’s onCreate() method.

Kotlin




  registerReceiver(broadcastReceiver, new IntentFilter("TIMEZONE_CHANGED"));
// broadcastReceiver is the object of any BroadClass receiver Service


Prevention:

Unregistered the broadcast receiver from Activity or Fragment’s onPause() or onDestroy() method can help developers to prevent memory leaks.

6. Improper Use of Threads

Threads are a very important part of any programming language. For managing tasks in the background or in concurrent Threads are very useful. Thread helps developers to manage multiple tasks in parallel or manage tasks in the background. Sometimes wrong use of threads can take applications into an infinite state which ultimately result in app crash or memory leaks.

Below example shows how we can create reference to Runnable thread in our activity.

Kotlin




override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
  
        val customRunnable = CustomRunnable(this)
        handler.postDelayed(customRunnable, 2000)
 }


Prevention:

Using WeakReferences with Threads helps developers to prevent memory leaks. Lets understand this with the use of example.

Kotlin




private class CustomRunnable(activityContext: MainActivity) : Runnable {
        private val mainActivityReference = WeakReference(activityContext)
  
        override fun run() {
            val activity = mainActivityReference.get()
           }
    }


7. Improper Fragment Transition Method Use

Google recommends to use Single Activity Architecture where developers create single activity and multiple Fragments for multiple screens. Using fragments in the place of Activities helps to make applications light and consume less memory. Fragment transitions provide Add and Replace methods to navigate from one screen to another screen.

  • Add method adds another fragment/screen in stack to and display the fragment which is on top.
  • Replace methods replace the fragment/screen and keep the current fragment on top always.
  • Using Add methods unnecessarily consumes lots of memory and leads to Memory leaks.

Prevention:

Developers must not use Add fragment until it’s necessary, rather they should use replace method which will consume very less memory and prevent memory leaks

8. Database Cursors

An application where developers need to store data in databases, developers create the object of the database, open them for reading and writing data and forget to close the database after completion of its ussage. Open database references consume a lot of memory and are often responsible for memory leaks.

Example to create database object with kotlin

Kotlin




val cursor: Cursor = dbHelper.readableDatabase.query()


Prevention:

Closing the database that was opened by developer for read or write operation after completion of uses can help developers to prevent memory leaks that occur due to database open references.

Example snippet to close database

Kotlin




cursor.close()


9. Unused Resources

Resources that have been declared and initialised but not being used anymore can waste memory and can lead to memory leaks.

Kotlin




Var drawable = AppCompatResources.getDrawable(context, R.drawable.icon);


Prevention:

Releasing resources which are not being used anymore in application can help to save memory and prevent memory leaks

10. Inner Classes

Inner classes in kotlin hold reference to their outer classes. Classes that are non-static are implicitly associated with an instance of the outer class. If inner classes are used as listeners and not properly detached then it will hold reference even after router classes are not needed.

Example:

Kotlin




class MainActivity: AppCompatActivity() {
  
  private val innerClass: InnerClass = InnerClass()
  
  class InnerClass {
    // ...
  }
  
  // ...
}


Prevention:

If the inner class is declared as static then it won’t hold references to the outer class. Using Weak reference will also help to prevent memory leaks.

Kotlin




class MainActivity: AppCompatActivity() {
  
  private val innerClass: InnerClass = InnerClass(this)
  
  class InnerClass(activity: MainActivity) {
    private val activityReference: WeakReference < MainActivity > = WeakReference(activity)
  
    fun doSomething() {
      val activity = activityReference.get()
      activity?.let {
        // Perform some operation using the outer class instance
      }
    }
  }
}


Must Check:

Conclusion

Android development is ruling huge market space in Mobile technology, so the memory leaks are essentials to ensure stability and reliability of applications. Following prevention techniques mentioned in the article can help to reduce memory leaks to some context.

By following the best approach to memory management developers can create Android applications that not only meet users expectations but also give seamless experience to applications. Along with following best practices there are many tools like Android Profiler, LeakCanary, MAT that can help developers to identify memory leaks during the development process.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads