I am getting this weird OutOfMemoryError that occurs although the dalvikvm reports enough heap space. Logs:
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 the outofmemory occurs the dalvikvm reports about 10mb free memory after gc. The allocation is for a 800k bitmap. I doubt that there is a race condition between gc and bitmap decoding here, because the reported free memory of dalvik didn't drop below 8mb free memory in all log statements of the last 20-30 seconds before the crash.
The problem occurs on a Samsung Galaxy Tab 2 10.1 running Android 4.1.2. I'm using a modified version of the ImageFetcher classes from the Google I/O app (2012), so I'm already doing stuff like inJustDecodeBounds when loading images to optimize sampleSize option.
As per documentation in Managing Bitmap Memory Android allocates Bitmap pixel data in the dalvik heap (since Android 3.0), so why does decoding the bitmap cause an outofmemory with 10mb free memory?
Has anyone seen this before or may have an idea what's happening?
EDIT: Per request here is the image loading code from the Google I/O app 2012. In my app I am just calling
mImageFetcher.loadImage(myUrl, myImageView);
EDIT2: The relevant image decoding methods extracted from above link to make clear that I am already using sample size optimizations:
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;
}
About OutOfMemory (OOM) on ~850000 bytes allocation when you have 10 Mb free, that is most certainly due to memory fragmentation there is no guarantee that the heap has one continous chunk of memory bigger than 850000 bytes and this is why you get the OOM.
Seems strange that you still get the error, you seem to have done some optimizations already, do you really release all memory you hold? I mean you have 38 Mb used heap, what are contained in that memory?
Have you tried looking at image loading libraries, such as, for instance picasso ?
Where one could such things as: Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").fit().into(imageView);
(This downloads and caches the image and fits and draws into an imageView, neat!)
Update
It seems like ICS and later Android versions are not letting your VM go to the total size of the heap. I've seen the same thing in my app,
You can add
android:largeHeap="true"
to your <application> which gives your app a much larger heap. Not nice but works...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With