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

Android开发中不缩放Bitmap且避免OOM的高效压缩方案

问题根因

你当前代码触发OOM是两个实现错误导致的,和是否缩放Bitmap没有直接关系:

  1. MediaStore.Images.Media.getBitmap() 默认会以ARGB_8888格式完整解码全尺寸原图,单张4000*3000分辨率的图解码后就会占用近48MB内存,大尺寸原图这一步就已经逼近内存阈值。
  2. *PNG是无损压缩格式,compress()方法传入的quality参数对PNG格式完全无效,不管你传0还是100,最终输出的都是和原始像素数据体积基本一致的无损内容,你写的compress(Bitmap.CompressFormat.PNG, 50, ...) 等于没做任何压缩。后续执行toByteArray()时需要申请一块和压缩前数据差不多大的连续内存,很容易触发OOM。
不重缩放Bitmap的压缩落地方案

以下方案完全不修改Bitmap的原始宽高尺寸,同时可以把内存占用压到安全线内:

  • 第一步:解码阶段优化内存占用,不缩放也能砍半内存
    弃用直接调用getBitmap()的写法,改用BitmapFactory自定义解码配置,保持inSampleSize=1(即1:1采样不缩放),不需要透明通道的场景把像素存储格式改成RGB_565,单个像素内存占用从4字节降到2字节,直接把Bitmap本身的内存砍半。
    // 和现有代码风格一致的Java实现
    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Bitmap.Config.RGB_565; // 无透明通道场景使用,内存直接减半
    options.inSampleSize = 1; // 采样率为1=完全不缩放,保留原始尺寸
    InputStream inputStream = getContentResolver().openInputStream(fileUri);
    Bitmap compressedImageFile = BitmapFactory.decodeStream(inputStream, null, options);
    inputStream.close();
    
    如果需要保留图片透明通道,把配置改回ARGB_8888即可,后续压缩步骤依然可以大幅降低输出体积。
  • 第二步:替换无效的PNG压缩格式
    不要用PNG做质量压缩,根据系统版本选择对应有损压缩格式,quality参数设为50-70区间肉眼几乎看不出画质差异,输出体积可以降到原PNG的1/10甚至更低:
    • Android 12(API31)及以上:用Bitmap.CompressFormat.WEBP_LOSSY,同画质下体积比JPEG小30%,还支持透明通道
    • 低版本兼容:用Bitmap.CompressFormat.JPEG,全版本系统兼容性最好
  • 第三步:避免全量字节数组的内存申请
    不要把压缩后的内容全部攒在ByteArrayOutputStream里最后转成字节数组——这个操作需要申请和压缩后文件等大的连续内存,就算压缩后只剩几MB,连续内存不足也会触发OOM。
    如果你后续是要存本地、上传服务端,直接把压缩流输出到目标载体即可,全程只需要几KB的缓冲区,完全不会占大内存:
    // 示例:直接压缩输出到本地文件,不在内存中留存全量数据
    File targetFile = new File(getCacheDir(), "compressed_img");
    FileOutputStream fos = new FileOutputStream(targetFile);
    // 直接写入文件流,不需要ByteArrayOutputStream做中转
    compressedImageFile.compress(Bitmap.CompressFormat.JPEG, 60, fos);
    fos.flush();
    fos.close();
    // 用完及时回收Bitmap内存
    compressedImageFile.recycle();
    
    如果后续逻辑必须拿到字节数组,可以给ByteArrayOutputStream初始化时提前设置合理的初始容量,避免反复扩容产生内存碎片,同时拿到字节数组用完后及时释放引用,帮助GC回收。

注意:如果你要求必须保留无损画质,那不存在可以大幅降低内存占用的方案——无损压缩的压缩比上限极低,全尺寸无损图的像素数据本身就会占用固定大小的内存,要全量加载必然要占对应内存空间,这种场景要么接受有损压缩,要么必须做尺寸缩放。

功能场景示例

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:54:23