I get this weird OutOfMemoryError that raises, although dalvikvm reports enough heap space. Magazines:
12-09 14:16:05.527: D/dalvikvm(10040): GC_FOR_ALLOC freed 551K, 21% free 38000K/47687K, paused 173ms, total 173ms 12-09 14:16:05.527: I/dalvikvm-heap(10040): Grow heap (frag case) to 38.369MB for 858416-byte allocation 12-09 14:16:05.699: D/dalvikvm(10040): GC_FOR_ALLOC freed 6K, 21% free 38832K/48583K, paused 169ms, total 169ms 12-09 14:16:05.894: D/dalvikvm(10040): GC_FOR_ALLOC freed 103K, 20% free 38929K/48583K, paused 169ms, total 169ms 12-09 14:16:05.894: I/dalvikvm-heap(10040): Forcing collection of SoftReferences for 858416-byte allocation 12-09 14:16:06.074: D/dalvikvm(10040): GC_BEFORE_OOM freed 6K, 20% free 38922K/48583K, paused 182ms, total 182ms 12-09 14:16:06.074: E/dalvikvm-heap(10040): Out of memory on a 858416-byte allocation. 12-09 14:16:06.074: I/dalvikvm(10040): "AsyncTask #2" prio=5 tid=17 RUNNABLE 12-09 14:16:06.074: I/dalvikvm(10040): | group="main" sCount=0 dsCount=0 obj=0x42013580 self=0x5f2a48d8 12-09 14:16:06.074: I/dalvikvm(10040): | sysTid=10101 nice=10 sched=0/0 cgrp=apps/bg_non_interactive handle=1591062136 12-09 14:16:06.074: I/dalvikvm(10040): | schedstat=( 7305663992 4216491759 5326 ) utm=697 stm=32 core=1 12-09 14:16:06.074: I/dalvikvm(10040): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 12-09 14:16:06.074: I/dalvikvm(10040): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:619) 12-09 14:16:06.074: I/dalvikvm(10040): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:691)
As you can see right before exiting the memory, dalvikvm reports free memory 10 MB after gc. The distribution is intended for a bitmap of 800 bits. I doubt that there is a race condition between gc and raster decoding, because the reported dalvik free memory did not fall below 8 MB free memory in all log statements in the last 20-30 seconds before the failure.
The problem occurs on the Samsung Galaxy Tab 2 10.1 running Android 4.1.2. I use a modified version of the ImageFetcher classes from the Google I / O application (2012), so I already do things like inJustDecodeBounds when loading images to optimize the sampleSize parameter.
According to the documentation in Raster Memory Management, Android allocates Bitmap pixel data in the dalvik heap (since Android 3.0), so why does decoding a bitmap cause outofmemory with 10 MB of free memory ?
Has anyone seen this before, or may have an idea of what is happening?
EDIT: Upon request, here is the code to download the image from the Google I / O 2012 application. In my application I just call
mImageFetcher.loadImage(myUrl, myImageView);
EDIT2: Relevant image decoding methods extracted from the link above to show that I am already using sample size optimization:
public static Bitmap decodeSampledBitmapFromDescriptor( FileDescriptor fileDescriptor, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFileDescriptor(fileDescriptor, null, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return BitmapFactory .decodeFileDescriptor(fileDescriptor, null, options); } public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { // Calculate ratios of height and width to requested height and // width final int heightRatio = Math.round((float) height / (float) reqHeight); final int widthRatio = Math.round((float) width / (float) reqWidth); // Choose the smallest ratio as inSampleSize value, this will // guarantee // a final image with both dimensions larger than or equal to the // requested height and width. inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio; // This offers some additional logic in case the image has a strange // aspect ratio. For example, a panorama may have a much larger // width than height. In these cases the total pixels might still // end up being too large to fit comfortably in memory, so we should // be more aggressive with sample down the image (=larger // inSampleSize). final float totalPixels = width * height; // Anything more than 2x the requested pixels we'll sample down // further. final float totalReqPixelsCap = reqWidth * reqHeight * 2; while (totalPixels / (inSampleSize * inSampleSize) > totalReqPixelsCap) { inSampleSize++; } } return inSampleSize; }