Memory Management in Android
Have you ever thought of making your application memory efficient or you ever wondered what really causes OutofMemoryException or IllegalStateException while developing an application ?.Every app needs memory as a resource to do its work. To make sure each Android App has enough memory, Android system needs to manage memory allocation efficiently.
In this article, I’ll show you how to ensure that your latest Android app project uses as little memory as possible. We’ll look at how to scour your project for some of the most common memory-related problems, and how to gather more information about any problems you do discover, so you’ll be in a better position to fix them.
And just in case it turns out that your app isn’t suffering from any specific memory problems, I’ll also share some general tips for optimizing your app’s memory usage.
Analyzing the Heap with Memory Profiler
Android devices have a finite amount of heap space that can only accommodate a certain number of objects. When the system is running low on memory, it’ll trigger a GC event, so if you spot unusual GC activity then the next step should typically be to take a closer look at the kind of objects your app is allocating on the heap.
The Memory Profiler is a component in the Android Profiler that helps you identify memory leaks and memory churn that can lead to stutter, freezes, and even app crashes. It shows a real-time graph of your app’s memory use, lets you capture a heap dump, force garbage collections, and track memory allocations.You can access it by :
View > Tool Windows > Android Profiler (you can also click Android Profiler in the toolbar).
- A button to force a garbage collection event.
- A button to capture a heap dump.
- A button to record memory allocations. This button appears only when connected to a device running Android 7.1 or lower.
- Buttons to zoom in/out of the timeline.
- A button to jump forward to the live memory data.
- The event timeline, which shows the activity states, user input events, and screen rotation events.
- The memory use timeline.
If your device is running Android 7.1 or lower, click Record memory allocations in the Memory Profiler toolbar. While recording, Android Monitor tracks all allocations that occur in your app. When you’re done, click Stop recording to view the allocations.Once you select a region of the timeline (or when you finish a recording session with a device running Android 7.1 or lower), the list of allocated objects appears below the timeline, grouped by class name and sorted by their heap count.
Once you select a region of the timeline, the list of allocated objects appears below the timeline, grouped by class name and sorted by their heap count.
To inspect the allocation record, follow these steps:
- Browse the list to find objects that have unusually large heap counts and that might be leaked. To help find known classes, click the Class Name column header to sort alphabetically. Then click a class name. The Instance View pane appears on the right, showing each instance of that class, as shown in below image.
- In the Instance View pane, click an instance. The Call Stack tab appears below, showing where that instance was allocated and in which thread.
- In the Call Stack tab, click on any line to jump to that code in the editor.
Capture a heap dump:
A heap dump shows which objects in your app are using memory at the time you capture the heap dump. Especially after an extended user session, a heap dump can help identify memory leaks by showing objects still in memory that you believe should no longer be there. Once you capture a heap dump, you can view the following:
- What types of objects your app has allocated, and how many of each.
- How much memory each object is using.
- Where references to each object are being held in your code.
- The call stack for where an object was allocated. (Call stacks are currently available with a heap dump only with Android 7.1 and lower when you capture the heap dump while recording allocations.)
To capture a heap dump, click Dump Java heap in the Memory Profiler toolbar. While dumping the heap, the amount of Java memory might increase temporarily. This is normal because the heap dump occurs in the same process as your app and requires some memory to collect the data.
In the list of classes, you can see the following information:
- Alloc Count: Number of allocations in the heap.
- Native Size: Total amount of native memory used by this object type (in bytes). This column is visible only for Android 7.0 and higher.
- You will see memory here for some objects allocated in Java because Android uses native memory for some framework classes, such as Bitmap.
- Shallow Size: Total amount of Java memory used by this object type (in bytes).
- Retained Size: Total size of memory being retained due to all instances of this class (in bytes).
At the top of the class list, you can use the left drop-down list to switch between the following heap dumps:
- Default heap: When no heap is specified by the system.
- App heap: The primary heap on which your app allocates memory.
- Image heap: The system boot image, containing classes that are preloaded during boot time. Allocations here are guaranteed to never move or go away.
- Zygote heap: The copy-on-write heap where an app process is forked from in the Android system.
The list of objects in the heap is arranged by class name, by default. You can use the other drop-down to switch between the following arrangements:
- Arrange by class: Groups all allocations based on class name.
- Arrange by package: Groups all allocations based on package name.
- Arrange by call stack: Groups all allocations into their corresponding call stack. This option works only if you capture the heap dump while recording allocations. Even so, there are likely to be objects in the heap that was allocated before you started recording, so those allocations appear first, simply listed by class name.
To inspect your heap, follow these steps:
- Browse the list to find objects that have unusually large heap counts and that might be leaked. To help find known classes, click the Class Name column header to sort alphabetically. Then click a class name. The Instance View pane appears on the right, showing each instance of that class
- In the Instance View pane, click an instance. The References tab appears below, showing every reference to that object.
- In the References tab, if you identify a reference that might be leaking memory, right-click on it and select Go to Instance. This selects the corresponding instance from the heap dump, showing you its own instance data.
Memory leak :
What is a memory leak? It’s a failure in a program/application to release discarded memory, causing impaired performance or failure.Or we can say its a failure to release reachable memory which is no longer needed for your application to function correctly.No objects should stay in memory longer than they should. They occupy valuable resources which could otherwise be used for things that provide real value to the user. For Android specifically, it causes the following problems.
- Interruptions in UI rendering and processing of events.
- The system runs short of memory and results in an out-of-memory crash.
- Unable to identify or reproduce the issues while testing.Thus it makes very hard to rectify it.
Where is the leak and how to fix it?
Frankly, there is no straightforward answer for this.If you have a basic understanding of how memory leak occurs, you should be able to pinpoint the culprit quite easily. Common causes for Android are:
- An object within your activity or fragment outlived the lifecycle of the activity, probably due to the usage of static objects or background process or callbacks.
- Avoid using non-static inner classes in an activity if instances of the inner class could outlive the activity’s lifecycle.
- Passing activity context to external classes or static instance. For non-UI related request, it’s safer to use application’s context.
- An observer which outlive the activity holding references to the activity.
- Database cursor which is not closed.
- Forget to unregister listeners.
- When Android operating system holds a focus reference to an input even though the activity is closed.
- LocationServices causes memory leaks when it had the reference to the Activity or Fragment
How to avoid leaks?
- Limit the usage of static variables in activities.
- When you pass your activity as a listener to a singleton object or an x-manager instance, make sure you understand what the other object does with the activity instance you passed in. Clear the reference (set the listener to null) if necessary on Activity onDestroy.
- Use static inner classes instead of normal inner classes
- Usage of WeakReference is a good choice to prevent leak as it can be garbage collected anytime when the system wants.
- Always try to clear the worker threads and unregister listeners in the onDestroy method of your Activity
We have discussed about memory management and memory leaks.Good understanding of memory allocation can help us to build quality and efficient apps. You can just see how easy to accidentally leak a massive amount of memory although in the worst case this will cause your app to run out of memory and crash.Garbage collection is a very expensive operation and will cause noticeable slowdown for the user. Stay aware of potential reference chains when instantiating objects in your Activities and test for memory leaks often!