Android了解堆大小

Joh*_* P. 30 heap android virtual-machine dalvik ddms

我是Android开发的新手,我似乎无法掌握Java Out of Memory异常.我知道这意味着我的应用程序已经超过了VM的预算,但经过Google搜索这么多次后,我似乎仍然没有掌握这个概念.我担心我的应用程序会占用太多内存,因为每个屏幕有六个按钮选择器,每个选择器有两个位图,根据属性选项卡每个大约20 kb.在我的根目录G2x上,我已将VM预算设置为12mb,重新启动了我的手机并运行了我的应用程序,没有任何问题.我在每个onDestroy()上取消绑定drawables并暗示GC也在这里运行.在模拟器中使用应用程序一段时间后,在我的DDMS屏幕上单击"原因GC",结果为ID = 1,堆大小6.133 MB,分配2.895MB,自由3.238 MB,%使用47.20,#对象52,623.

这是我不明白发生了什么,我的模拟器设置为24MB的VM.那个数字在哪里?我遇到的实际问题是,如果我将模拟器设置为16MB的VM,我的应用程序会因为内存不足异常而在第二个活动上崩溃.为什么我的手机上的VM设置为12 MB,或者我的旧HTC Magic手机上有12 MB的VM存量?你们还认为我的应用占用了太多内存吗?我不知道这些DDMS号码是否好.谢谢你的时间.

至于我的代码,我有XML布局中指定的每个图像,除了向它们添加侦听器之外,我不会以编程方式对它们执行任何操作.我在这里找到了这段代码,我已将它添加到我拥有的每个活动中......

@Override
protected void onDestroy() {
    super.onDestroy();

    unbindDrawables(findViewById(R.id.myRootLayout));
    System.gc();
}

private void unbindDrawables(View view) {
    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }
    if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }
        ((ViewGroup) view).removeAllViews();
    }
}
Run Code Online (Sandbox Code Playgroud)

否则,我所做的就是将onClickListeners添加到具有PNG背景的按钮.我想学习如何以编程方式指定按钮背景,但我需要选择功能,如焦点,按下,非聚焦但按下等,以使按钮背景根据用户交互而变化.我已经回顾了关于这个的文档,但它看起来势不可挡,这就是为什么我认为我从这里开始管理堆的基础知识,并努力在代码中指定选择器.这可能没有意义但是有一个"健康"的内存分配量,应用程序可以分配而不会接近内存不足异常?例如,如果一个应用程序分配6MB应该没问题,但8MB会推动它,在内存分配方面有这样的界限吗?再次感谢Alex Lockwood的回复我将再次阅读并重新阅读,直到这些内容对我有意义

Ale*_*ood 51

在仿真器/设备上设置VM预算时,您正在做的是告诉堆允许的最大大小.在运行时,当Dalvik VM从操作系统请求系统内存时,堆的大小会动态增长.Dalvik VM通常首先分配一个相对较小的堆.然后在每次GC运行后,它会检查有多少可用堆内存.如果可用堆与总堆的比率太小,则Dalvik VM将向堆中添加更多内存(最大配置堆大小).

话虽这么说,你在DDMS屏幕上没有看到"24 mb"的原因是因为堆没有增长到它的最大大小.这使Android可以充分利用手持设备上已有的少量内存.

至于为什么你的应用程序在模拟器而不是你的手机上崩溃,这看起来很奇怪(你确定这些数字是正确的吗?).但是,您应该记住,内存是动态管理的,并且总内存利用率是根据许多外部因素(执行垃圾收集的速度/频率等)确定的.

最后,由于我上面提到的原因,很难确定您的应用程序基于您在上面提供的单行信息管理内存的程度.我们真的需要看一些你的代码.OutOfMemoryError但是,绝对值得担心,所以我肯定会考虑你的应用程序的内存使用情况.您可能会考虑的一件事是在运行时通过调用inSampleSize使用BitmapFactory该类来对位图图像进行采样.这有助于减少加载可绘制位图所需的内存量.要么你或者你可以降低你的drawables的分辨率(虽然每个20 kb对我来说听起来不错).

  • 重新分辨率评论“每个 20 kb 听起来不错” - AFAIK,*文件大小*是多少并不重要(对于压缩得更好的图像来说会更小),重要的是*尺寸*是什么;在内存中,对于全彩,每个像素需要 4B,对吧?因此,在加载图像时,根据当前设备的实际需要的大小调整图像大小非常重要[android docs - 将缩小版本加载到内存中]。 (2认同)

tbr*_*aun 18

即使您的应用程序未达到"24mb"(因设备而异)堆限制,您仍可能崩溃,因为Android需要一段时间来增加应用程序的堆空间.

在我的情况下,我在很短的时间内创建和转储了几张图像.

我常常得到OutOfMemoryError.

似乎Android不够快,无法为我的应用增加堆空间.

我相信我通过使用largeHeap清单文件中的设置解决了这个问题.启用该设置后,Android每次增加堆时都会留下更多可用内存,从而最大限度地降低达到当前限制的可能性.

我不使用24mb限制,但这个largeHeapconf非常方便.

您只需要设置您largeHeap="true"的应用程序标签AndroidManifest.xml

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:theme="@style/AppTheme" >
Run Code Online (Sandbox Code Playgroud)

尽管如此,确保在处理图像时要小心,例如@Alex Lockwood建议.

  • 请尽量使用largeHeap ="true".因为使用它可能会对您的应用程序性能产生不利影响.因为您告诉系统增加最大堆限制.当发生这种情况时,垃圾收集将花费更多时间.如果您检查日志,则可以看到GC暂停时间会更长.理想情况下它应该在2-5ms之间.在这种情况下,它甚至可以变化甚至高达30-45ms.因此,不要因为内存不足而将大堆属性设置为true.使用它作为最后一步.否则它将成为一个性能. (18认同)