I'm noticing a crash (in an external native library that does some image processing) when I pass it the pixel data returned from bitmap.getPixels().
If I package the image in the app, in the drawables folder and load the Bitmap with
BitmapFactory.decodeResource()
then grab the pixel data with
bitmap.getPixels()
there's no crash, and everything works as expected. However, if I load the same image from the file system with
BitmapFactory.decodeFile()
then grab the pixels with
bitmap.getPixels()
and hand that off, the native lib crashes.
Is there a difference between the way these two calls process the image into a Bitmap?
Reading the Android sources There is one interesting diffrence: The decodeFile method may call a different native bitmap decoder if the passed file is an asset, while the decodeResource will never do this.
if (is instanceof AssetManager.AssetInputStream) {
bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),
outPadding, opts);
However, the crash is most likely a bug in your native code. Messing up the stackframe with bad pointers and/or buffer overruns typically results in weird crashes like this. Try to check all your native code that runs before the crash and see if you can spot any memory issues like that.
Related
I am developing an application that includes image processing ( grayscale , Bw filte ,object detection ,color adjustment ,level adjustment ).
As you know, new mobile phones takes high quality images with large sizes.Due to memory limitations, it is difficult to image processing and outofmemoryException occurs frequently .So I've moved compeletely image proccessing from Java layer to JNI as follows:
Mat file loaded in jni by source file path.
Proccessing ....
Result mat are stored in sd card.
Result image loaded in inSampledSize bitmap as preview.
OutOfMemoryException does not occur with this method in image proccessing .
but sometime when image have very large dimensions , Activity closed automattically during image processing without any exception and it's cause did not specify when debugging.
Why is this happening? And How can I fix this?
Excuse me for my english.
There are two things you could two :
First check if the problem happens while doing the image processing, if yes try to offload it from main thread and do it in a separate thread (may be an async task to start with). For more info on this refer this
Out of Memory Issue happens easily when you try set the high resolution images(bitmap) to the ImageView. If you are doing this you should lower the resolution before setting it to the ImageView. For more info on this please refer this link and also this stackoverflow post.
I'm trying to copy part of the source image. I've decoded the resource into bitmap with inScaling option turned off so I can crop from real image size but I'm getting outOfMemoryErorr thrown out.
I've read my device (S3) memory with
Log.i("CropParams memory", String.valueOf(Runtime.getRuntime().maxMemory()));
and it's showing 64MB.
I would really like to crop from real image size and to know what exactly causes outOfMemoryError so I know how to manage this kind of situations. This particular image is 2448x3264 and has 3.41MB.
Why is this particular image causing this error?
Thanks
See my answer on another question on how to dump the heap memory when you get an OutOfMemoryError.
With the Hprof file you should be able to analyze the memory usage as described here.
I think looks like a job for the Region decoder.
http://developer.android.com/reference/android/graphics/BitmapRegionDecoder.html
Just instantiate it with any of the newInstance api:s, then call decodeRegion for the region you are interested in.
I am trying to process a bmp image obtained from Android's camera intent through the following steps:
Obtain bmp image from intent
Convert bmp image to Mat object for OpenCV processing (problem starts here)
Do needed OpenCV processing (through sending Mat object, obj, as obj.getNativeObjAddr() to native processing, or perform it locally in java).
Convert Mat object back to bmp
The problem is indeed not novel. I have found countless similar questions online, none of which seem to resolve the situation however.
Results (problem)
The intention is to display the processed image (that undergoes the above 4 steps) in an ImageView object. After running, the ImageView however remains unchanged and logcat emits the following warning on reaching the line calling Utils.bitmapToMat()
W/System.err(3872): java.lang.IllegalArgumentException: mat == null
Code
Below is the code's outline that is used in the onActivityResult method (resultant_bmp is the acquired bmp from the camera intent. It displays successfully on its own).
filePath is the file path, name and extension included, of resultant_bmp.
The first 3 lines following the starting if condition are from here, where its use seems to work fine in the mentioned question.
Bitmap resultant_bmp /*image from camera*/,
bmp /*image after opencv processing*/;
Mat rgb_img, gray_img;
if (OpenCVLoader.initDebug()) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Config.RGB_565;
resultant_bmp= BitmapFactory.decodeFile(filePath, options);
/****************** Problem starts HERE ******************
Last point reachable before Logcat states:
W/System.err(4460):java.lang.IllegalArgumentException: mat == null
After this point, the program doesn't crash, but expected results
in the imageView (last line of code) do not result.
**********************************************************/
Utils.bitmapToMat(resultant_bmp, rgb_img);
Imgproc.cvtColor(rgb_img, gray_img, Imgproc.COLOR_RGBA2GRAY);
/*Do opencv processing (on gray_img) here*/
Utils.matToBitmap(gray_img, bmp);
imageView.setImageBitmap(bmp);
}
Previous attempts& research
I found a similar problem here and tried, as recommended, to push the file libopencv_java.so to system/lib on the device, using adb in command line and received the error:
failed to copy 'libopencv_java.so' to 'system/lib/libopencv_java.so': Read-only file system
This question considers the same problem domain in the current question; the code provided above follows a similar pattern as that suggested there, which still doesn't work.
Based on this answer (as well as this aforementioned one), I added the following lines to the code:
System.loadLibrary("opencv_java");
System.loadLibrary("libopencv_java");
I have added the OpenCV library to the project properties; as well as the NDKROOT variable indicating where the NDK root path lies, as explained further here.
I've tried the image processing required (in step 3 above) in another working sample of OpenCV's, so the problem definitely lies within step 2 (above); conversion of a bmp to a Mat object.
There should be a simple solution around this, but I cannot seem to find it. Help would be much appreciated if possible.
Thank you for your time.
Have you initialized your mat variable ? I couldnt find it in provided code.
Add this before you try to convert to mat.
Mat rgb_img = new Mat();
Like many others I have the anoying VM budget problem. I am getting files from the sdcard and I decode it and comprimizes them using:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
The problem is that i get the bitmap each time i call the onCreate method. So after turning phone or starting the activity a couple of times it crashes. The only method I can find to avoid this is:yourBitmap.recycle(), but you can not catch a recycled Bitmap.
I need an expression that still manage to show the the bitmap even after it would normaly crashed on VM budget. I am showing the bitmap as a drawable, so the classic unbindDrawables solotion does not work. I need an expression that eighter comprimices the Bitmap to almost nothing, or that recycles and shows a new Bitmap of the same size.
try reading this:
http://developer.android.com/training/displaying-bitmaps/index.html
and watching this:
http://www.google.com/events/io/2011/sessions/memory-management-for-android-apps.html
also , about drawables, see that you don't have any references to them after they are not needed . drawables can cause memory leaks.
Let's say I have loaded an image in a bitmap object like
Bitmap myBitmap = BitmapFactory.decodeFile(myFile);
Now, what will happen if I load another bitmap like
myBitmap = BitmapFactory.decodeFile(myFile2);
What happens to the first myBitmap? Does it get Garbage Collected or do I have to manually garbage collect it before loading another bitmap, eg. myBitmap.recycle()?
Also, is there a better way to load large images and display them one after another while recycling on the way?
The first bitmap is not garbage collected when you decode the second one. Garbage Collector will do it later whenever it decides. If you want to free memory ASAP you should call recycle() just before decoding the second bitmap.
If you want to load really big image you should resample it. Here's an example: Strange out of memory issue while loading an image to a Bitmap object.
I think the problem is this: On pre-Honeycomb versions of Android, the actual raw bitmap data is not stored in VM memory but in native memory instead. This native memory is freed when the corresponding java Bitmap object is GC'd.
However, when you run out of native memory, the dalvik GC isn't triggered, so it is possible that your app uses very little of the java memory, so the dalvik GC is never invoked, yet it uses tons of native memory for bitmaps which eventually causes an OOM error.
At least that's my guess. Thankfully in Honeycomb and later, all bitmap data is stored in the VM so you shouldn't have to use recycle() at all. But for the millions of 2.3 users (fragmentation shakes fist), you should use recycle() wherever possible (a massive hassle). Or alternatively you may be able to invoke the GC instead.
You will need to call myBitmap.recycle() before loading the next image.
Depending on the source of your myFile (E.g. if it is something you have no control over the original size), when loading an image instead of just simply resampling some arbitrary number, you should scale the image to the display size.
if (myBitmap != null) {
myBitmap.recycle();
myBitmap = null;
}
Bitmap original = BitmapFactory.decodeFile(myFile);
myBitmap = Bitmap.createScaledBitmap(original, displayWidth, displayHeight, true);
if (original != myBitmap)
original.recycle();
original = null;
I cache the displayWidth & displayHeight in a static that I initialized at the start of my Activity.
Display display = getWindowManager().getDefaultDisplay();
displayWidth = display.getWidth();
displayHeight = display.getHeight();
Once bitmap had been loaded in memory , in fact it was made by two part data.
First part include some information about bitmap , another part include information about pixels of bitmap( it is maked up by byte array).
First part exisits in Java used memory, second part exisits in C++ used memory. It can use each other's memory directly.
Bitmap.recycle() is used to free the memory of C++.
If you only do that,the GC will collection the part of java and the memory of C is always used.
Timmmm was right.
according to :
http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html
In addition, prior to Android 3.0 (API Level 11), the backing data of a bitmap was stored in native memory which is not released in a predictable manner, potentially causing an application to briefly exceed its memory limits and crash.