【发布时间】:2013-12-26 15:34:47
【问题描述】:
尽管 dalvikvm 报告了足够的堆空间,但我得到了这个奇怪的 OutOfMemoryError。日志:
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)
正如您在内存不足发生之前看到的那样,dalvikvm 在 gc 之后报告了大约 10mb 的可用内存。分配用于 800k 位图。我怀疑这里的 gc 和位图解码之间存在竞争条件,因为在崩溃前最后 20-30 秒的所有日志语句中,报告的 dalvik 的可用内存并未低于 8mb 可用内存。
此问题出现在运行 Android 4.1.2 的三星 Galaxy Tab 2 10.1 上。 我正在使用 Google I/O 应用程序 (2012) 中的 ImageFetcher 类的修改版本,因此在加载图像以优化 sampleSize 选项时,我已经在执行 inJustDecodeBounds 之类的操作。
根据Managing Bitmap Memory 中的文档,Android 在 dalvik 堆中分配位图像素数据(自 Android 3.0 起),那么为什么解码位图会导致 10mb 空闲内存的内存不足?
有没有人以前见过这种情况或可能知道发生了什么?
编辑: 每个请求 here 是来自 Google I/O 应用程序 2012 的图像加载代码。 在我的应用中,我只是在打电话
mImageFetcher.loadImage(myUrl, myImageView);
编辑2: 从上面的链接中提取的相关图像解码方法表明我已经在使用样本大小优化:
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;
}
【问题讨论】:
-
您能分享代码以便我们为您提供帮助吗?
-
你需要回收你的位图
-
@Manitoba 添加了源链接
-
@ShakeebAyaz recycle 仅释放本机内存,文档称这仅适用于 3.0 以下的 Android 版本。如果文档有误,请纠正我。
-
您应该尝试提供有关您的整个应用程序的更多信息。系统不可能在平板电脑上仅占用 38 Mb 就杀死您的应用程序。你确定你没有使用一些本机内存吗?您的应用程序的限制对于 Native memory + java heap 是独一无二的。你在使用一些本地库吗?也许是opencv或gmaps?尝试使用 MAT 跟踪 java 总内存和本机内存使用情况wwboy6.wordpress.com/2012/12/09/android-ndk-memory-analyze