I'm not quite sure how much memory will be allocated to the following variable "bitmap",
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.example);
bitmap = Bitmap.createScaledBitmap(bitmap, 100, 100, true);
Say, the dimension of the original image is 1024*768 and some memory has been allocated to the bitmap. Then the bitmap was scaled to 100*100, and will the memory allocated to the variable "bitmap" be changed due to the change of the dimension?
A variable only ever takes up a small amount of memory (if any). A few bytes at most. A variable of an object type only uses enough memory to store a pointer to the object.
Objects pointed to by variables, however, can take up any amount of memory. createScaledBitmap creates a new bitmap so after your code is run there will likely be two bitmaps in memory. One of them (the original, larger one) however no longer has any live references (e.g. variables) pointing to it, so it will eventually be garbage collected.
Related
When a new bitmap variable is created to have the same value as an original bitmap variable, does it build a copy thereby taking memory cache space for two bitmaps or it only returns the original bitmap cache whenever it is called within the app?
An illustration is this;
public static Bitmap originalBmp;
public static Bitmap copyBmp;
originalBmp = ......;
copyBmp = originalBmp;
My question now is this;
in the memory cache, if originalBmp takes 2MB, does calling copyBmp = originalBmp; result in a total cache memory of 4MB or it maintains 2MB wherever yet copyBmp is called....just to know that there is no memory pile up with new bitmap variables taking values from originalBmp.
In Java, originalBmp and copyBmp point to objects. We often say they "are" objects, but that is a bit of verbal shorthand.
In your case, when you execute copyBmp = originalBmp;, both originalBmp and copyBmp will point to the same Bitmap object, not each to its own copy of that object. So, your 2MB Bitmap still consumes only 2MB, despite two fields pointing to it.
Note, though, that putting a 2MB Bitmap into a static field is dangerous. static fields are "intentional memory leaks". That 2MB cannot be freed up for use by other objects until all references to the Bitmap are gone. In your case, both originalBmp and copyBmp are static, so they will always point to your 2MB Bitmap, until you reset both of those fields to null (or point them to some other Bitmap). Be very careful when using static fields that you do not wind up consuming too much memory.
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.
I have done following things to handle my bitmaps in application:
LruCache for Bitmaps with size of 1/8 of memory
Using BitmapFactory.Options to calculate inSampleSize
Catching OOM when creating Bitmaps, calling evictAll and System.gc() there
Also there are AsyncTask decoding sometimes for Bitmaps
I use BitmapFactory.decodeFile and it looks like VM is not freeing Bitmaps fast enough from memory. I read somewhere that there might be bug using BitmapFactory.decodeFile so I tried to use BitmapFactory.decodeFileDescriptor, but there I randomly get following:
skia --- decoder->decode returned false
So is there something wrong with FileInputStream needed to fix here if I wan't to use BitmapFactory.decodeFileDescriptor or something else to do.
This has taken me too much time and I've read all solutions based on this and how Google advices Bitmap handling and I've come to dead end.
Thanks.
Using large Bitmap always there is a chance to get Out Of Memory Exception..
So to handle go through Android blog
http://developer.android.com/training/displaying-bitmaps/index.html
And always recycle the Bimap
ImageView mImage;
Drawable toRecycle = mImage.getDrawable();
if ( toRecycle != null && toRecycle instanceof BitmapDrawable ) {
if ( ( (BitmapDrawable) mImage.getDrawable() ).getBitmap() != null )
( (BitmapDrawable) mImage.getDrawable() ).getBitmap().recycle();
}
I ended up using SoftRefences with Bitmap here. Now I can see GC freeing my unused Bitmaps all the time when fast scrolling GridView which draws them.
Tested setting my LruCache size full memory size and still didn't get OOM.
Penalty using this method is not that visible, my GridView scrolls pretty smoothly considering it's drawing very custom image.
System.gc() won't help you and doesn't guarantee anything.
If you absolutely sure, that evicted bitmaps are no longer needed and there is no reference to them anywhere (will catch "Can't draw recycled bitmap" exception otherwise) I would suggest you to add an EvictionListener to your LRU cache and call bitmap.recycle() on every evicted value.
Can't remember if default LRU cache provides convenience methods for setting eviction listener, but if not, it's extremely easy to extend it and add required functionality.
P.S. I would advice against WeakReferences since you lose any control of your bitmaps and purpose of LRU. Even if you load 8 bitmaps that nicely fit in your 1/8 of memory, but screen can only display 4 of them at a time (ImageViews holding a strong references to Bitmaps) gc will clear remaining 4 as soon as possible. And I really mean ultra fast. You'll have to reload bitmap for each new row (in case of ListView) you are displaying. And every bitmap that went offscreen will have to be reloaded again.
can any one explain how the inPurgable option works when it set to true ?
from the documentation
If this is set to true, then the resulting bitmap will allocate its
pixels such that they can be purged if the system needs to reclaim
memory. In that instance, when the pixels need to be accessed again
(e.g. the bitmap is drawn, getPixels() is called), they will be
automatically re-decoded. For the re-decode to happen, the bitmap
must have access to the encoded data, either by sharing a reference
to the input or by making a copy of it.
My interpretation of this is it will either keep a reference to the filename
the bitmap pixels were loaded from or it will make a copy of the pixels
somewhere. For the former, can I expect drawBitmap to then perform a
potentially slow IO operation in my onDraw method if the bitmap was purged?
For the latter, how is the copy made and what is the memory usage impact of
this?
I have big bitmap covering whole screen. After reading a lot of posts about memory leaks and performance I noticed 2 problems:
1. Generating big bmp costs time.
2. Caching big bmp /static bmp in activity/ speeds up activity start, but causes problem with references and memory.
My decision is to move bitmap in Application class.
How will this reflect on references and garbage collection?
Do I have to make bitmap in application class static?
UPDATE:
Please don't comment 'same memory' in both cases. My question is related to references and garbage collecting.
It's not important how you load bitmap when it is in memory.
It still takes the same amount of memory.