android createBitmap OOM when ((freeMemory > bitmapSize) && (nativeFreeHeap < bitmap size))

发布于 2024-11-18 08:38:33 字数 3717 浏览 2 评论 0 原文

在 Android 2.2 上,以下程序会产生 OOM。总之,该程序执行以下操作:

  1. 分配一个大数组,该数组需要本机堆增长到接近其最大大小。
  2. 垃圾收集数组。
  3. 尝试创建大小大于剩余本机空闲堆的位图。

为什么会因 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)

On Android 2.2, the following program produces an OOM. In summary, the program does the following:

  1. Allocates a big array that requires native heap to grow close to its maximum size.
  2. Garbage collects the array.
  3. Attempts to create a bitmap of size larger than the remaining native free heap.

Why does this fail with an OOM? It's as if the native heap will only allocate memory for bitmaps in memory previously unallocated.

The output appears below the program. Thanks in advance.

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());
    }
}

Here's the output:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

罗罗贝儿 2024-11-25 08:38:33

我认为您在这里深入了解了未记录的行为 - 您无法指望在不同的 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文