I wrote the code to create bitmap from a given byte array. Below is the sample code:
Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(imgData));
However, it takes around 15-20 ms. Similarly, there might be other operation which can consume time in an android application. In adb logcat, I see GC_ALLOC_FREE....paused 14ms, growing heap size etc etc.
My question: Is there a way to pre-allocate memory in android applications so it can avoid GC being invoked so many time? I searched online and I got to know that usually game apps do it for performance optimization, however, could't find an example on how to do it.
EDIT:
As per the below suggestion, I have 'bm' as the member variable and create ByteBuffer object.
Bitmap bm = bm.createBitmap(width, height, Bitmap.Config.ARGB_8888);
ByteBuffer bb = ByteBuffer.allocate(<length>);
Then the below code keep getting invoked over and over again:
bitmap.copyPixelFromBuffer(bb.put(data));
However, it gave me the same result and I still see GC_FOR_ALLOC freed...paused 15 ms.
Also, the above code of line gets invoked in a listener method and it gets the 'data' as an argument.
The edited code was actually right, however, I was generating some byte array in other part of my code which was making GC work hard.
#CommansWare: your response pointed me to the right direction. Thanks.
Why don't you create your bitmap using BitmapFactory.decodeByteArray? Then it does everything automagically for you. Also you can check out the extended version of that method that allows you to set the width and height (and other parameters) ahead of time.
Related
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.
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?
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 overridden the onDraw() method in a custom View. My method looks like following:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
data.lockData(); // uses reentrantlock
Bitmap bm = data.getBitmap();
if (bm != null) {
canvas.drawBitmap(bm,0,0,mPaint);
}
data.unlockData();
}
There is another thread that updates the bitmap, and this thread also uses the lockData() method to ensure serialized access to the bitmap. However, I see that the bitmap being drawn contains incomplete updates, i.e. it is being drawn to the screen while being in the middle of update by the other thread. I do not know the details of the Android drawing pipeline with sufficient detail (or actually with any detail:), but I assume this is due to that drawBitmap() does not actually draw the bitmap, but just places it into a draw operations queue with the pointer to the bitmap, and later another part of the system will use this pointer to copy the required part of the bitmap pixels to the buffer that will be displayed on screen. Therefore the actual drawing is not protected by the mutex.
There is a classical solution, i.e. double buffering, which I think could work in this type of situation. However, I still think that my draw thread might be so fast that it actually comes to update the buffer that is being drawn again before the actual draw has finished. Furthermore, my bitmap can be quite large, and allocating a separate buffer would be somewhat wasteful.
My questions are:
Is my above stated understanding about the reason for incomplete draws correct, i.e. the drawBitmap returns before the bitmap data has actually been copied to the display? Could you provide a reference for details on how the drawing works?
Is there a way to know when the bitmap has actually been drawn, and therefore it is again safe to modify the bitmap?
If double buffering is the only solution, how can I ensure that buffer1 has finished drawing before allowing the buffer1 to be updated again with new data?
I was not able to make the View drawing synchronized. One way it would have worked is to do the calculation from within the onDraw() method, i.e. Bitmap bm = data.getBitmap(); would do calculate the updated bitmap. The drawback of this is that this will block the UI thread for the duration of the calculation, resulting or example in missed input events, etc.
One way this can be overcome is to use a SurfaceView instead. There one can do the calculation and drawing in a separate thread, thus serializing the two operations, while still leaving the UI thread free.
would
image.setDrawingCacheEnabled(true);
do any good? Setting this to true enables you to pull a bitmap from the newly drawn canvas. Seems like that would be synchronized with the actual drawing so that when you subsequently do:
imageBitmap = image.getDrawingCache();
you would get a fully drawn image
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?