Clueless About a (Possible) Android Memory Leak
android, bitmap, eclipse-memory-analyzer, java, memory-leaks
Solution
It looks like the reason why the `Remainder` is growing is the growth of the number of `Activity` instances in the back stack (e.g. 13 instances of the "List" `Activity` + 13 instances of the "Main" `Activity`).
I've changed my Navigation Drawer so that when the user clicks the "Home" button (which takes him to the App's "Dashboard") I set the `Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK` flags: the Activity is re-used and the back stack is cleared (as recommended by the Android guidelines, actually). In fact, I should have done this already as I don't want several instances of the Dashboard ("Home") activity to be created.
By doing this I can see that the Activities are destroyed and allocated heap size (including the "`Remaining`" slice) decreases:
While fixing this, I also noticed that one of my Activities and a Bitmap used by it were not being destroyed, even if the back stack had been cleared (leak). After analysing with MAT I concluded that the source of this sub-problem was a reference to an `ImageView` that I kept in the `Activity`. By adding this code to the `onStop()` method, I've managed to get both the activity and `Bitmap` to be destroyed:
@Override
protected void onStop() {
super.onStop();
ImageView myImage = (ImageView) findViewById(R.id.myImage );
if(myImage .getDrawable() != null)
myImage.getDrawable().setCallback(null);
RoundedImageView roundImage = (RoundedImageView) findViewById(R.id.roundImage); // a custom View
if(roundImage.getDrawable() != null)
roundImage.getDrawable().setCallback(null);
}
I then generalized all my `Activity` and `FragmentActivity` so that they call `unbindDrawables(View view)` in `onDestroy()`:
private void unbindDrawables(View view)
{
if (view.getBackground() != null)
{
view.getBackground().setCallback(null);
}
if (view instanceof ViewGroup && !(view instanceof AdapterView))
{
for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
{
unbindDrawables(((ViewGroup) view).getChildAt(i));
}
((ViewGroup) view).removeAllViews();
}
}
Thanks to @NickT for pointing me in the right direction.
Problem
I’ve been facing some annoying `OutOfMemoryErrors`, even after making sure that all my Bitmaps are properly scaled etc. In fact, the issue doesn’t seem to be related to Bitmaps at all, but I may be wrong. For testing and error-isolation purposes, I’ve been switching between two activities (let’s call them Main and List) using my Navigation Drawer (not using the back button). I can see in the DDMS that the allocated memory increases around 180 KB every time I return. I’ve done memory dumps and used eclipse MAT to analyze 3 different points in time: I suspect a memory leak but I can’t really find out its cause. According to the memory dumps, it looks like it’s the “Remainder” and `java.lang.FinalizerReference` that keep increasing. The user in this question also has a lot of `FinalizerReferences` in his memory dump, but the answer isn't quite clear. The Leak Suspects Report I made in the last point in time isn’t very helpful as it suspects of `android.content.res.Resources` and `android.graphics.Bitmap` which don’t seem to be growing over time: In one of the reports (sadly, not present here) I've seen 13 instances of `android.widget.ListView` pointed as a potential leak suspect. These memory increases happen with any transition between activities (not just the Main and List I used in this example). How can I find the (non-obvious?) memory leak? I’ve been scratching my head for a long time so any help and tips would be great. EDIT: Bitmaps (@OrhanC1): I've commented any `Bitmap` instantiations in the two activities mentioned above and the memory still increases. The memory dump still shows some bitmaps but I believe they're related to resources and not actual bitmaps allocated by me. Regarding custom fonts (@erakitin): I'm using them, but I'm keeping a single instance of each `Typeface` in my `Application` context (`public class MyApp extends Application`) using a singleton. I've tried commenting any references to the fonts in the two activities mentioned above and the memory still increases. I don't think I'm leaking the `Context` (@DigCamara): I don't hold any static references inside these two Activities, I'm using the `Application` context instead of the `Activity`'s except in an adapter. If I stay in the same `Activity` and do some screen rotations, the memory doesn't increase. Based on @NickT's comment: I can see I have many instances of both activities. Could these memory increases be just the result of an increase in the number of activities of the back stack and not a memory leak (I though the OS dealt with that, apparently not)? If I use the `FLAG_ACTIVITY_REORDER_TO_FRONT` intent flag then the memory only increases until all different activities have been instantiated (once). Useful for this matter: Android not killing activities from stack when memory is low.