android createBitmap OOM when ((freeMemory > bitmapSize) && (nativeFreeHeap < bitmap size))
在 Android 2.2 上,以下程序会产生 OOM。总之,该程序执行以下操作:
- 分配一个大数组,该数组需要本机堆增长到接近其最大大小。
- 垃圾收集数组。
- 尝试创建大小大于剩余本机空闲堆的位图。
为什么会因 OOM 而失败?就好像本机堆只会为之前未分配的内存中的位图分配内存。
输出显示在程序下方。提前致谢。
public class OomTest extends Activity {
private static final String OOM_TEST = "OomTest";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
printDiag();
Log.i(OOM_TEST, "Allocating big int array.");
int[] bigIntArray = new int[11000000];
printDiag();
bigIntArray = null;
Log.i(OOM_TEST, "Garbage collecting.");
System.gc();
printDiag();
Log.i(OOM_TEST, "Creating 4 meg bitmap bitmap.");
Bitmap bitmap = Bitmap.createBitmap(1000, 1000, Config.ARGB_8888);
printDiag();
Log.i(OOM_TEST, "Done.");
}
private void printDiag() {
Log.i(OOM_TEST, "maxMemory: " + Runtime.getRuntime().maxMemory());
Log.i(OOM_TEST, "totalMemory: "
+ Runtime.getRuntime().totalMemory());
Log.i(OOM_TEST, "freeMemory: "
+ Runtime.getRuntime().freeMemory());
Log.i(OOM_TEST, "nativeHeapSize: "
+ android.os.Debug.getNativeHeapSize());
Log.i(OOM_TEST, "nativeHeapAllocatedSize: "
+ android.os.Debug.getNativeHeapAllocatedSize());
Log.i(OOM_TEST, "nativeHeapFreeSize: "
+ android.os.Debug.getNativeHeapFreeSize());
}
}
这是输出:
I/ActivityManager( 2501): Start proc com.example.android.oomTest for activity
com.example.android.oomTest/.OomTest: pid=25242 uid=10031 gids={1015}
I/OomTest (25242): maxMemory: 50331648
I/OomTest (25242): totalMemory: 2953200
I/OomTest (25242): freeMemory: 479512
I/OomTest (25242): nativeHeapSize: 3600384
I/OomTest (25242): nativeHeapAllocatedSize: 3585800
I/OomTest (25242): nativeHeapFreeSize: 14584
I/OomTest (25242): Allocating big int array.
D/dalvikvm(25242): GC_FOR_MALLOC freed 634 objects / 51344 bytes in 48ms
I/dalvikvm-heap(25242): Grow heap (frag case) to 44.573MB for 44000016-byte allocation
D/dalvikvm(25242): GC_FOR_MALLOC freed 34 objects / 1992 bytes in 60ms
I/OomTest (25242): maxMemory: 50331648
I/OomTest (25242): totalMemory: 46997472
I/OomTest (25242): freeMemory: 575224
I/OomTest (25242): nativeHeapSize: 3600384
I/OomTest (25242): nativeHeapAllocatedSize: 3578408
I/OomTest (25242): nativeHeapFreeSize: 23560
I/OomTest (25242): Garbage collecting.
D/dalvikvm(25242): GC_EXPLICIT freed 65 objects / 44002952 bytes in 52ms
I/OomTest (25242): maxMemory: 50331648
I/OomTest (25242): totalMemory: 46997472
I/OomTest (25242): freeMemory: 44576440
I/OomTest (25242): nativeHeapSize: 3600384
I/OomTest (25242): nativeHeapAllocatedSize: 3575784
I/OomTest (25242): nativeHeapFreeSize: 24600
I/OomTest (25242): Creating 4 meg bitmap bitmap.
E/dalvikvm-heap(25242): 4000000-byte external allocation too large for this process.
E/GraphicsJNI(25242): VM won't let us allocate 4000000 bytes
D/AndroidRuntime(25242): Shutting down VM
W/dalvikvm(25242): threadid=1: thread exiting with uncaught exception (group=0x4001d7d0)
E/AndroidRuntime(25242): FATAL EXCEPTION: main
E/AndroidRuntime(25242): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
E/AndroidRuntime(25242): at android.graphics.Bitmap.nativeCreate(Native Method)
E/AndroidRuntime(25242): at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
E/AndroidRuntime(25242): at com.example.android.oomTest.OomTest.onCreate(OomTest.java:26)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为您在这里深入了解了未记录的行为 - 您无法指望在不同的 Android 版本或设备上获得一致的任何答案。
我的猜测是系统正在授予您的应用程序最大进程大小。进程大小由 dalvik 堆和本机堆组成(当然还要加上一些开销)。您已将 dalvik 堆扩展至最大。垃圾收集在 dalvik 堆中创建了空间,但所有进程的空间都分配给 dalvik 堆,因此对于本机堆不可用,因此本机堆中没有空间来容纳位图对象。
我相当确定这种行为与以前(或只是其他?)版本的 Android 不同,其中 dalvik 堆无法扩展超过总进程大小限制的大约一半。
I think you're deep into undocumented behavior here-- you wouldn't be able to count on any answer you get being consistent across different Android versions or devices.
My guess is that the system is granting your app a maximum process size. The process size consists of the dalvik heap and the native heap (plus some overhead, of course). You've expanded the dalvik heap to the maximum. Garbage collecting created space in the dalvik heap, but all the process's space is allocated to the dalvik heap and is therefore unavailable to the native heap, so there isn't room in the native heap to accomodate the bitmap object.
I'm fairly certain this behavior differed in previous (or just other?) releases of Android, where the dalvik heap could not expand beyond about half of the total process size limit.