As title says, I have about eight acitivies with layout full of high-res images. On weaker android devicies with low RAM memory it opens each activity alone, but when I try open another, it crashes. But when I restart app and open that activity, it works. What should I do to clean apps memory from these images from first activity to be able to open another activity? Does onDestroy() clean it?
If it like resource images in xml layout, you don't need to clean up them, Android will do it for you. But if you use some big bitmaps objects.
Bitmpap bmp; // not null
bmp.recycle();
bmp = null;
final boolean bmpIsRecycled = bmp.isRecycled()
// Returns true if this bitmap has been recycled.
Free the native object associated with this bitmap, and clear the reference to the pixel data. This will not free the pixel data synchronously; it simply allows it to be garbage collected if there are no other references. The bitmap is marked as “dead”, meaning it will throw an exception if getPixels() or setPixels() is called, and will draw nothing. This operation cannot be reversed, so it should only be called if you are sure there are no further uses for the bitmap. This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap.
And actually when your app crashes, what error log do you have? Maybe it's not related with memory leak?
Related
I have a memory leak of bitmaps causing out of memory. I ran the tests on Android 5.0 (Samsung S5). I have investigated the issue using Android Studio (1.5.1 + 2.0.0 Preview 7). The HPROF memory dump show that there are multiple byte[] which correspond exactly to a particular huge bitmap I use temporarily. If I make sure I keep references to the bitmap then Android Studio shows me a Bitmap with 11MB dominating size and a byte[] with 11MB Shallow size. If I don't keep references to the bitmaps then some of the bitmaps become garbage collected and some end up as byte[] without incoming references (ie. no parents) as shown in image.
I have tested my app enough to know with reasonable confidence that this 11MB byte[] is a roughly 2891x1000x4 bitmap I have had in memory. Some smaller bitmaps also get leaked and show up with no incoming references.
The bitmaps above are allocated in a subactivity. If I return to the parent activity (in same process and thus dalvikVM) and force 2x GC then memory is released. Multiple manual GC's does not release the memory before quitting the sub-activity.
It seems to be independent on whether I run bitmap.recycle() or not. It happens very rarely if I just stand in the same place in the app and run the code generating the huge bitmap out of the same view. If I move around the app and generate the bitmap from different views its a lot more frequent, like from 50% leaks to 10% leaks.
Is it an Android bug?
Do I use the bitmaps wrong in some way and Android studio just fails to show me a correct view of the memory?
Is my understanding correct that if there are no parents in the reference tree below (see image), then the memory should be released by garbage collector (hence its an Android Bug or studio bug or hprof dump-bug?)
I found a solution to the leak, though Android Studios reporting of the unreferenced byte[] is still a mystery.
It appears that the ImageView in which i did
imageView.setImageBitmap(bitmap)
will prevent GC of the bitmaps underlying byte[]. bitmap.recycle() does not help, nor does unbinddrawables() as written about in numerous locations
if (imageView.getBackground() != null) {
imageView.getBackground().setCallback(null);
}
setImageBackground(imageView, null);
imageView.setImageBitmap(null);
imageView.setImageDrawable(null);
When I removed the view from the viewhiearchy and removed all my own references to the view, then the byte[] was GC'ed and the leak was gone.
My application needs creating a bitmap object for a certain view every 1 min
private static Bitmap mBitmap = null;
public static Bitmap getBitmap()
{
//create new bitmap object
return mBitmap;
}
My question is, do I need to destroy mBitmap before creating new bitmap ?
You don't have to manually destroy a Bitmap after you used it, but you can help the garbage collector do its job. There is a method called recycle(), the following paragraph is from its documentation:
Free the native object associated with this bitmap, and clear the
reference to the pixel data. This will not free the pixel data
synchronously; it simply allows it to be garbage collected if there
are no other references. The bitmap is marked as "dead", meaning it
will throw an exception if getPixels() or setPixels() is called, and
will draw nothing. This operation cannot be reversed, so it should
only be called if you are sure there are no further uses for the
bitmap. This is an advanced call, and normally need not be called,
since the normal GC process will free up this memory when there are no
more references to this bitmap.
In earlier Android versions Bitmaps were handled natively by the OS. This was the original reason for the recycle() method. Since the Bitmaps were handled outside of the Java VM the garbage collector could not automatically free the memory of unused Bitmaps, you can find more information about that here but the important part is this:
On Android 2.3.3 (API level 10) and lower, the backing pixel data for
a bitmap is stored in native memory. It is separate from the bitmap
itself, which is stored in the Dalvik heap. The pixel data in native
memory is not released in a predictable manner, potentially causing an
application to briefly exceed its memory limits and crash. As of
Android 3.0 (API level 11), the pixel data is stored on the Dalvik
heap along with the associated bitmap.
So if you want to support Android 2.3.3 (Gingerbread) or below you have to be careful with Bitmaps. You always have to remember to call recycle() otherwise your application may crash in an unpredictable manner.
If you only support Android versions above Android 3.0 then you don't have to worry about freeing Bitmap memory, but if you create a lot of Bitmaps and/or are getting close to OutOfMemoryExceptions then calling recycle() on all not needed Bitmaps can still have
a considerable positive effect.
If you want to learn more about handling Bitmaps then visit this link.
I hope I could help you and if you have any further questions please feel free to ask.
You should never do that, you should either:
Reuse the Bitmap if size is always the same (clearing and reusing)
Caching bitmaps using an LRU cache
If you absolutely need to destroy it every time call Bitmap.recycle() and then create a new one, but this is a very very bad thing to do.
In my Fragment I have a custom view that extends LinearLayout. Let's call it gallery
In that custom view I have 5 ImageView. Each contains an image loaded from web.
When my Fragment is no longer required I destroy references in onDestroyView()
#Override
public void onDestroyView() {
super.onDestroyView();
gallery = null;
}
I noticed, that my app leaks memory and using DDMS and MAT I found that those 5 Bitmap in those ImageViews are still in memory. Well that's no good. So on the next step I did this in my mini gallery
#Override
protected void onDetachedFromWindow() {
super.onDestroyView();
imageView1 = null;
...
imageView5 = null;
}
That didn't help either. On my last attempt I did this
#Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
imageView1.setImageBitmap(null);
imageView1 = null;
...
imageView5.setImageBitmap(null);
imageView5 = null;
}
That helped. Memory was freed and memory leaks were plugged up.
Now my question is - why? Why, when my gallery was not referenced by anything it was not GC'ed? And even more - when ImageView was not references it's content - Bitmap - was never GC'ed? Should I forcefully clean image bitmap?
I noticed that in other custom views where ImageView is used I had a similar problem. What are best practices for such cases?
As we all know that the its uncertain when GC is called and as #Farhan rightly said calling system.gc() too doesn't guarantee that objects will be garbage collected, we cannot really rely upon it. Also its not recommended to do the cleanup thyself.
So, finding solution to this issue particularly for Bitmaps I landed up to this function from the Bitmap class, which says
public void recycle ()
Added in API level 1
Free the native object associated with this bitmap, and clear the reference to the pixel data. This will not free the pixel data synchronously; it simply allows it to be garbage collected if there are no other references. The bitmap is marked as "dead", meaning it will throw an exception if getPixels() or setPixels() is called, and will draw nothing. This operation cannot be reversed, so it should only be called if you are sure there are no further uses for the bitmap. This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap.
Even tough it is said that it should not be called. The important lines about it noticed are Free the native object associated with this bitmap, and clear the reference to the pixel data. This will not free the pixel data synchronously; it simply allows it to be garbage collected if there are no other references. which states that calling this method will make the bitmap garbage collected.
Searching more on this I found a long discussion on the same issue faced by many, here.
And amongst the discussion the I found a solution posted by Sandeep Choudhary, who gives a small workaround with details using Bitmap.recycle() here.
GC will be get called when there is a need. like os was running low on memory, then it will call gc.. and gc will then check all unreferenced objects and clear them.
You only need to make sure, you are not keeping the reference unnecessarily.
On Android pre-honeycomb, Bitmaps have freaky memory issues because their data isn't stored in the VM. As a result it isn't tracked or removed by the GC. Instead it is removed when Bitmap.recycle() is called (and that is also done automatically in the Bitmap's finalizer).
This leads to some problems when doing image caching. When a bitmap is due to be evicted, I can't simply call recycle() on it, because I have no idea if anyone else is using it.
My first thought was to do System.gc() just before I load each bitmap. That way, hopefully orphaned Bitmaps will be finalized and the native memory freed. But it doesn't work. Edit: Actually it does sort of work. I had my System.gc() in the wrong place, after moving it, and halving my cache size (to what seems like a ridiculously small 2 MB of uncompressed bitmap data), my app no longer seems to crash (so far)!
My next thought was to implement manual reference counting, by subclassing Bitmap and calling ReferenceCountedBitmap.decrementCount() in all my activities' onDestroy() methods. But I can't because Bitmap is final.
I am now planning a BitmapManager which keeps WeakReference's to the bitmaps, and has methods like:
public void using(Bitmap bm);
public void free(Bitmap bm);
which count the references.
Does anyone have any experience or advice handling this? Before you suggest it, I can't ignore 80% of the market.
Well, I solved this with a bitmap manager, where I save the referencing views. In a map-like structure bitmap -> list of views.
Before I call recycle() on a bitmap, I first set all the references from the views to null (otherwise it will throw bitmap recycled exception).
Manual garbage collection, as you say, doesn't work for bitmaps pre-honeycomb, since they are allocated in the native heap and even with System.gc() you can't make assumptions when this memory will be released.
I have a bitmap that I load from the SD card by allowing the user to choose a picture to display. Once the bitmap is created, I set the Bitmap in an ImageView:
mBitmap = Bitmap.createBitmap(Media.getBitmap(this.getContentResolver(), mPictureUri));
mImageView.setImageBitmap(mBitmap);
This works fine. But, if I change the screen orientation from portrait to landscape, and back again a few times, I always get an OutOfMemory exception.
In onPause, I call mBitmap.recycle(), and then on onResume, I call the above code again to create the bitmap and set the ImageView. Since I'm recycling the image each time, how can I get an OutOfMemory error?
In any case, since that failed, I found a post that said to try using onRetainNonConfigurationInstance() and getLastNonConfigurationInstance(). See post Save cache when rotate device. I changed my code to work this way, and I still get an error. Changing the code, I had the call to getLastNonConfigurationInstance() in onCreate(), and removed all code in onPause and onResume.
Can someone tell me what the problem is, or provide some way to simply load an image, and then be able to pause and resume the Activity without running out of memory? Thanks.
Try reducing the size of your bitmap. How big is it? Use BitmapFactory.options.
Also instead of using "this instance". See the article about memory leaks:
http://android-developers.blogspot.com/2009/01/avoiding-memory-leaks.html
The memory leaks could be due to holding on to the context instance which in turn contains references to all the objects from the Activity before it was destroyed.
The article explains it better.
You should reduce size of the images because there is 16MB per app, if you have large bitmaps being recreated, they could accumulate to 16MB before they are garbage collected or if there are memory leaks.