android 中的 OOM(内存不足异常)是如何发生的?

How OOM(out of memory excepetion) happens in android?

我正在尝试在 ImageView 中显示来自画廊或从相机捕获的图像。我开始在这个过程中得到 OOMs。所以我决定找出它是如何工作的。所以我尝试了不同尺寸的图像,这里是观察结果,

我试图将 19KB 的图像加载到 ImageView 中,但收到以下错误消息。 无法分配 4915212 字节的分配和 570452 个空闲字节和 557KB,直到 OOM 我得到了一个 2MB 的图像 无法分配 31961100 字节的分配,其中有 16777120 个空闲字节和 29MB,直到 OOM 2MB

为什么 19KB 的图像需要几乎 4.6MB 的主内存,而 2MB 的图像需要 30MB 的主内存space?

PS:我找到了很多解决方案,例如根据显示对图像进行下采样,其中 none 解释了这种行为。

在Android中,图像的每个像素都需要 4 个字节的内存。因此,如果您用 5 兆像素的图像创建 Bitmap,则需要大约 20MB。因此,您应该计算在不加载完整分辨率的情况下显示图像所需的样本大小。

即使图像文件只有19KB,Bitmap对象也会占用更多内存。

尝试创建一个静态方法来计算所需的样本量:

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) {

    final int halfHeight = height / 2;
    final int halfWidth = width / 2;

    // Calculate the largest inSampleSize value that is a power of 2 and keeps both
    // height and width larger than the requested height and width.
    while ((halfHeight / inSampleSize) > reqHeight
            && (halfWidth / inSampleSize) > reqWidth) {
        inSampleSize *= 2;
    }
}

return inSampleSize;
}

然后在加载完整图像之前先检查图像的边界:

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
    int reqWidth, int reqHeight) {

// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);

// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}

有关此内容的更多信息,请参阅开发人员指南: https://developer.android.com/training/displaying-bitmaps/load-bitmap.html

理想情况下,您将使用 ARGB_8888 作为位图。这意味着为每个像素分配 4 个字节(每个像素用于 A、R、G、B)。这意味着加载 1024x768 图像需要 1024*768*4 = 3145728 B = 3072 KB = 3 MB。这就是使用巨大内存的原因。以下信息取自文档:http://developer.android.com/reference/android/graphics/Bitmap.Config.html

Bitmap.Config.ALPHA_8 - 每个像素都存储为单个半透明 (alpha) 通道。

Bitmap.Config.ARGB_4444 -此字段在 API 级别 13 中已弃用。由于此配置的质量较差,因此建议改用ARGB_8888。

Bitmap.Config.ARGB_8888 - 每个像素存储在 4 个字节上。

Bitmap.Config.RGB_565 - 每个像素存储在 2 个字节上,仅对 RGB 通道进行编码:红色以 5 位精度存储(32 个可能值),绿色以 6 位精度存储(64 个可能值),蓝色以 5 位精度存储。