I work with several large drawables and I don't know how to manage memory leaks.
I tracked the heap size of my application and it doesn't stop to grow (as the allocated memory).
It is especially the "byte array (byte[])" type which grows up and never decrease. (in the DDMS Heap view on Eclipse)
My application is composed of one activity which uses fragments.
Those fragments are displaying several large images.
I tried to set drawables callback to null, set drawables to null, clear my volatile cache (which prevent my app from doing too many disk IO) when I pop back a fragment but the heap never decrease.
In fact, each time I call :
Drawable.createFromResourceStream(context.getResources(), value, new FileInputStream(f), f.getName(), opts);
the heap grows up. How can I free memory ?
Thanks !
A memory leak happens when Java finds objects in the memory that are referenced by your code which is preventing the Garbage Collector from freeing this memory. A common cause in Android is referencing the Activity context rather than the Application context. Make sure your context references the Application (i.e. use getApplicationContext rather than using this. Check this video for explanation on Memory leaks and also check this question.
The question seems answered but a post by Romain Guy seems relevant to get more info: Avoiding Memory Leaks.
Apparently, if you (for example) set a drawable as a background image to a text view by using setBackgroundDrawable* (thus attaching the drawable to the view) then change the orientation (destroying the Activity and redrawing the UI) the drawable will still have access to the old activity (after the old activity's destruction), thus creating a memory leak.
*(as a side note - setBackgroundDrawable has been deprecated since API level 16)
Related
In android app, images can be changed through run-time (e.g. layout-bg, ImageButton-src, Button-bg, ..etc), so what happens to the old image in the terms of memory occupation? is it removed or still occupy a portion from the memory? and if it's not removed, how can I clear the memory from this image?
UI part of android is mainly written in Java -- once all references to a bitmap is gone, the bitmap will be flagged for garbage collection. If you do not use a bitmap texture, and you have no reference to that bitmap anywhere in the code the memory will be freed immediately. Please be careful about memory leak in android. Read this:
http://android-developers.blogspot.ca/2009/01/avoiding-memory-leaks.html
Several Activitys in my app display images in a ListView where each row of the ListView contains an ImageView.
An example of this would be a search screen where the user searches, gets results, and a picture of each result is shown.
I'm trying to weigh the cost/benefits of implementing a global LruCache vs having each Activity contain its own local LruCache.
Here are my two main problems. Both revolve around the fact that my app is quite large, meaning there are quite a few screens which show these images. Also, my app has the popular side menu way of navigating. Because of this, I could open the menu, tap Activity B, open the menu, tap Activity A, open the menu... etc. and create an Activity stack of ABABABABABABABAB indefinitely.
Global
Won't Activitys with ImageViews using Bitmaps from a global LruCache contain references to these Bitmaps? Suppose the user navigates away from this Activity by clicking some Button. That Activity is now on the Activity stack and still holds references to those Bitmaps. If the LruCache pops a Bitmap off, can that Bitmap really be reclaimed when an ImageView in some Activity on the stack holds a reference to it?
I had previously created my own custom cache. If I called recycle() on a Bitmap and then the user hit the back button to go back to some Activity on the stack that contained an ImageView set to that Bitmap, the app would crash. This is why I believe ImageViews on Activitys on the stack still hold references to Bitmaps.
Local
As I mentioned earlier. My app is quite large, and side menu style of navigation allows the user to create rather large Activity stacks. This would create a lot of LruCaches. And, since you have to declare the size of the LruCache when you initialize it, there wouldn't seem to be any good way of picking a size.
Thoughts? Suggestions?
At this point I think I have to do global, but I don't know how to solve the Activity stack reference problem. I can't imagine this isn't a problem many apps haven't run into. I don't know why I'm not finding information about it.
I'm trying to weigh the cost/benefits of implementing a global
LruCache vs having each Activity contain its own local LruCache.
Global LruCache is the way to move forward, since the same set of bitmaps might be referred in different activity instances. The LruCache can be defined part of Application. If the activity stack can host multiple instances of the same activity (like ABABABAB..), then creating a LruCache locally in that activity will be a bad idea. Very soon Out Of Memory situtation will be reached, as LruCache in each activity instance reserves the defined amount of memory in Dalvik VM. Assume, application memory is 32Mb and you decide LruCache size as 4Mb i.e. 1/8th. Now when we create nearly 7 instances of Activity A, then memory consumption will go to 7*4=28Mb, that itself might trigger OOM.
Won't Activitys with ImageViews using Bitmaps from a global LruCache
contain references to these Bitmaps?
Yes ImageView will also have a strong reference to the bitmap. If the reference is maintained in LruCache, then the reference count will be 2 at that moment.
If the LruCache pops a Bitmap off, can that Bitmap really be reclaimed
when an ImageView in some Activity on the stack holds a reference to
it?
No the bitmap memory can't be reclaimed, as still some ImageView is have a strong reference to it.
At this point I think I have to do global, but I don't know how to
solve the Activity stack reference problem.
LruCache main role is holding strong reference to the bitmap which are more frequently used. So that if there is no strong reference held by any ImageView, the bitmap is prevented from being garbage collected.
Also remember, for Android 2.3.3 and lower versions, you need to implement reference counting mechanism, in order to recycle the bitmaps.
Here are some newbie memory management observations to which I would like
hear an experienced opinion.
It seems that setting android:backgound="#drawable/xyz" in a xml
layout causes memory loss in my app. The respective activities keep
stacking up until I get an OOM error. This is especially true if I rotate
the device orientation.
However, if I load the same resource with setBackgoundResource(), and then clear the
callback and set the background reference to null, there is no leak whatsoever.
that is, first in onCreate()
mMainLayout.setBackgroundResource(R.drawable.background_general_android);
and then in onDestroy()
mMainLayout.getBackground().setCallback(null);
mMainLayout.setBackgroundDrawable(null);
Is this roughly correct, or am I missing something essential?
This would only happen if you keep a copy of the drawables in a static cache for instance. You might also be leaking your activities and setting the drawables to null simply hides the problem for a little longer. You should use a tool like MAT to inspect the content of your heap and figure out what's going on.
So I have an APP that loops and continuously draws many png files to a canvas. In the constructor for the thread, for some of the pngs I declare Drawable and some Bitmap handles and assign them (respectively) like so:
Drawablename = context.getResources().getDrawable(R.drawable.pngresource);
mBackgroundImage = BitmapFactory.decodeResource(res, R.drawable.bckgrnd);
Keep in mind I do both methods, MANY times. (even though most of the images are fairly small)
Well... the problem i'm getting is that when trying to start this app on older devices (specifically like the original droid and older) it force closes with the VM budget error.
From research, I've noticed that this seems to be a common problem. (The app runs fine on all newer devices such as droid x, every tablet at best buy, charge, atrix, etc.)
So my question is could I be doing something better?
Is one of these methods of referencing the pngs superior?
Also What exactly is happening here? I need to be able to reference the Image to draw at any time. In other words, at any given instant I could call Draw on one of the handles.
The fixes I've seen for similar problems involve calling the Garbage collector, but would that help me since I would need the Images later anyway? Or is this exclusively a problem with the way i'm referencing the pngs from the drawable folder?
Sorry if this is confusing, i'm a beginner.
If I called System.gc() after every reference would that help, even though the reference is still stored as a Drawable object?
The common fix:
Resize image size, for example: createScaledBitmap()...
Reduce image quality, Config.inSampleSize setting...
Remove all references to Bitmap objects when un-used (setting references to NULL, of course). If you don't do this, System.gc() will does nothing, remember this! and this method call does not guarantee that the memory will be freed right away.
I have many pictures in my #drawable directory which are connected to xml layout via background property:
i.e
<ImageButton android:background="#drawable/background1" ... />
I have many activities, so, when activity is destroyed (BACK is pressed), the heap isn't freed. So, the question is:
Does android load everything in the memory once and make heap free only when application is destroyed? How I can prevent in this case memory consumption ? Only through image compression or dynamically loading background and images?
I think Android has a its own garbage collector, but for proceed it its take sometimes instead of relevent momory as the object is not in use. And whenver the bitmap is created its memory occupied in native heap and heap garbage collector is to lazzy.
So if possible use dynamic Image loading instead of static, and try to use your own recycler or freed the memory of your bitmap.
EDIT:
The gc() does not handle so-called short lived objects as fast as we
would like.
Keep the number of view objects at a stable level*, and recycle them instead of destroying and creating new ones.
A nice post of Avoiding memory leaks by Roman Guys refer it.
If I am wrong please let me know. And please share some more information on this.
Thanks.