Do I still need to call Bitmap.Dispose() after Bitmap.Recycle()? Or just Bitmap.Dispose() is enough?
According to Android documentation Bitmap.Recycle() should be enough:
Free the native object associated with this bitmap, and clear the
reference to the pixel data.
Mono for Android documentation says exactly the same.
Also, this question gets a little further on how Bitmap.Recycle works.
Another solution could be to wrap in a using statement:
using (var bm = new Bitmap(..))
{
// Do stuff with the Bitmap here
}
Just remember that when you leave the scope of the using statement, the Bitmap will probably be garbage collected. So if you are just drawing it to a Canvas or something this is a nice way to do it.
Related
Here look at the below code,
for (String path : all_path) {
bmp = BitmapFactory.decodeFile(path);
bitmapList.add(bmp);
}
and this code is driving me crazy. As in each iteration BitmapFactory.decodeFile(path) is called and driving memory to its pick as a result OutOfMemory exception occurs. I tried to use recycle() old bitmap in the loop before decoding new bitmap but it means no sense. I searched for the answer about using bitmaps in loop but failed to find one. What should I do? anyone help please.
You are adding all bitmaps to a List. However you are using the same reference variable bmp for all bitmaps so in each iteration they get replaced.
But in the List all the bitmaps are being added. If there are many bitmaps then it will eventually result in OutOfMemoryError
Better do not add all bitmaps in a List.
Try to recycle the bitmaps you are not using.
If you use all the bitmaps than add them to a cache and use them later.
Next when you want to replace one you will replace just one not all of them.
The change from below requires a bit more work but it works as I used it with a lot of bitmaps.
Please take a look here:
I implemented once something like this:
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
Bitmaps can be huge. Why do you need to read them all to the memory? Normaly, you would read each bitmap on demand. Optionally, you can read thumbnails, which are much less memory demanding (BitmapFactory enables you to downsize the bitmap when reading - use BitmapFactory.Options, member inSampleSize).
Read this: http://developer.android.com/training/displaying-bitmaps/index.html
One would think that the second approach would be more efficient but I can't say that I see any improvement using it. Is there a difference between the following two ? (memmory wise ofcourse)
Bitmap bm=MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(), id, MediaStore.Images.Thumbnails.MINI_KIND, null);
bm=cropAndScaleBitmap(bm);
//use bm
vs
Bitmap bm=MediaStore.Images.Thumbnails.getThumbnail(getContentResolver(), id, MediaStore.Images.Thumbnails.MINI_KIND, null);
Bitmap b =cropAndScaleBitmap(bm);
bm.recycle();
//use b
Things to note here ...
Even though you have specified recycle, it will have any effect only
when the next GC is trigerred.
Other things to note
In pre-Honeycomb versions of Android the memory for bitmaps was (is) allocated from unmanaged memory.It will take at least 2 passes of GC to collect it. Another thing is - it is really difficult to trace - DDMS does not see it and neither does MAT.
Read this link https://developer.android.com/training/displaying-bitmaps/manage-memory.html. If api level >10,I don't think we need to call recycle.
Refer to this link ... It provides all details and the code sample for how to implement step by step.
https://developer.android.com/training/displaying-bitmaps/manage-memory.html
Hope this helps.
In your specific example (first one) you don't actually reuse the source, you just overwrite the value of the bm making it point to the new bitmap instead, in this case you can no longer call recycle on the source bitmap as you no longer have a reference to it.
I recommend using the second method to make sure the source bitmap is recycled.
The Bitmap class has a method copy() with the signature below:
public Bitmap copy(Bitmap.Config config, boolean isMutable)
Is there a performance difference between a mutable and an immutable Bitmap?
Romain Guy answered in the comments:
To answer the original question: no, there is no performance
difference. There are some optimizations we could implement for
mutable bitmaps though. Hopefully in a future release :)
There is no performance difference. This will not affect the performance of your app. If you want to perform any opration like rotation etc then i think the bitmap should be mutable...
On Application level, there is always a difference between immutable & mutable Bitmap resources.
You always get an immutable Bitmap from the resources. you need to convert them into mutable bitmap as per necessiti.
Bitmap Bitmap = BitmapFactory.decodeResource(....);
Bitmap mutableBitmap = immutableBitmap.copy(Bitmap.Config.ARGB_8888, true);
So probably there must be a performance issue in this reference.
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.
In my Android app, when I run one of my activities a second time, I get an OutOfMemoryError. I think I need to delete the bitmaps from the first time when the activity runs. But I don't know how I can do this. Thank you.
Try reading your Bitmaps from within your code. Place the Bitmaps in the res/drawable-hdpi folder. (there are different folders for different image qualities). Set up the Bitmap fields in your code:
Bitmap alpha;
Bitmap foo;
Now initialize the Bitmaps in the onResume():
Options options = new Options();
alpha = BitmapFactory.decodeResource(game.getResources(), R.drawable.youBitmapName, options);
foo = BitmapFactory.decodeResource(game.getResources(), R.drawable.youBitmapName2, options);
Options will give you the ability to downsample. (I'm not sure how big your images are, but you might also want to use the scaling methods then).
In the onPause, clean up resources by calling:
alpha.recycle();
alpha = null;
foo.recycle();
foo = null;
As soon as the onResume() method is called, the bitmaps will reinitialize.
Normally the garbace collector would call Bitmap.recycle() as soon as no more references point to that instance.
If you want to 'force' clean up your bitmaps, call recycle() on your own.
But I would suggest to look for a memoryleak first.
Null your bitmaps and call the Garbage Collector: System.gc(); and/or Runtime.getRuntime().gc();
Also provide more details about your code for better answers.