You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Java项目运行崩溃报java.lang.OutOfMemoryError,求解决方案

解决Android Bitmap加载导致的OutOfMemoryError问题

核心问题分析

从堆栈跟踪可以明确,OOM是在加载资源中的Bitmap时触发的——系统尝试分配近380MB内存来加载一张超大分辨率的图片,远超过当前可用内存。android:largeHeap="true"只是临时扩容,无法解决图片本身过大的根本问题。

具体解决方案

1. 检查并优化原始资源图片

  • 定位问题图片:根据堆栈最后一行TypedArray.getDrawable,排查布局文件、样式文件中引用的drawable(比如ImageView的src属性、主题背景等),找到对应的图片文件。
  • 压缩图片分辨率:用图片编辑工具(如Photoshop、GIMP)将图片压缩到适配设备屏幕的尺寸(比如手机屏幕最大分辨率通常在1080x2340左右),避免加载远超显示需求的超大图。
  • 放置到正确的资源目录:将图片放到匹配其分辨率的drawable目录(如xxhdpi/xxxhdpi),避免系统自动放大图片导致内存占用飙升。

2. 使用BitmapFactory.Options优化加载过程

手动加载图片时,通过采样缩小图片尺寸,同时调整像素格式减少内存占用:

// 获取屏幕尺寸
DisplayMetrics metrics = getResources().getDisplayMetrics();
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;

BitmapFactory.Options options = new BitmapFactory.Options();
// 先获取图片原始尺寸,不加载到内存
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.drawable.target_image, options);

// 计算采样率,确保加载后的图片尺寸不超过屏幕
int sampleSize = calculateSampleSize(options, screenWidth, screenHeight);

// 开启实际加载
options.inJustDecodeBounds = false;
options.inSampleSize = sampleSize;
// 如果图片不需要透明通道,使用RGB_565格式,内存占用比ARGB_8888减少一半
options.inPreferredConfig = Bitmap.Config.RGB_565;

// 加载优化后的Bitmap
Bitmap optimizedBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.target_image, options);

辅助计算采样率的方法:

private int calculateSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    final int originalWidth = options.outWidth;
    final int originalHeight = options.outHeight;
    int sampleSize = 1;

    if (originalHeight > reqHeight || originalWidth > reqWidth) {
        final int halfHeight = originalHeight / 2;
        final int halfWidth = originalWidth / 2;
        // 找到最大的采样率,确保缩放后的图片仍能覆盖需求尺寸
        while ((halfHeight / sampleSize) >= reqHeight && (halfWidth / sampleSize) >= reqWidth) {
            sampleSize *= 2;
        }
    }
    return sampleSize;
}

3. 避免Bitmap内存泄漏

  • 及时回收Bitmap:在Activity/Fragment销毁时,调用bitmap.recycle()并将引用置为null,释放内存。
  • 使用LruCache缓存Bitmap:复用已加载的Bitmap,避免重复分配内存:
// 设置缓存大小为应用最大可用内存的1/8
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;

LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
    @Override
    protected int sizeOf(String key, Bitmap bitmap) {
        // 返回Bitmap占用的KB数
        return bitmap.getByteCount() / 1024;
    }
};

// 存入缓存
bitmapCache.put("image_key", optimizedBitmap);
// 从缓存获取
Bitmap cachedBitmap = bitmapCache.get("image_key");

4. 移除android:largeHeap="true"

这个配置只是临时扩容,会掩盖内存管理的根本问题,且不同设备的大堆内存限制不同,优化图片加载后即可移除。


内容的提问来源于stack exchange,提问作者martine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 14:10:42