如何生成超大PNG/JPEG文件以测试Android ImageDecoder的OOM场景
动态生成高体积编码图片触发ImageDecoder OOM的实用方案
针对你需要在Android Instrumentation测试中触发ImageDecoder的OutOfMemoryError、同时不想仓库存储大文件的需求,以下是几种不增大分辨率就能生成高体积编码图片的实用方案:
方法1:生成无规律像素数据+PNG无压缩存储
普通随机像素仍存在压缩空间,故意生成相邻像素完全无相似性的位图,让压缩算法无从下手,再配合PNG的无压缩级别,能生成接近原始位图大小的编码文件:
- 核心逻辑:逐个像素生成与前一个像素完全互补的颜色,彻底消除重复模式
- Kotlin代码示例:
val width = 4096 val height = 4096 val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) val pixels = IntArray(width * height) for (i in pixels.indices) { // 翻转前一个像素的所有位,生成完全相反的颜色 val prevPixel = if (i == 0) 0 else pixels[i - 1] pixels[i] = prevPixel xor 0xFFFFFFFF } bitmap.setPixels(pixels, 0, width, 0, 0, width, height) // 用PNG压缩级别0(无压缩)保存 val outputStream = FileOutputStream(cacheDir.resolve("uncompressible.png")) bitmap.compress(Bitmap.CompressFormat.PNG, 0, outputStream) outputStream.close()
生成的文件大小接近原始位图(4096×4096×4≈64MB),足以触发OOM。
方法2:给编码文件追加冗余数据(最简高效)
不管原始压缩文件大小,直接在文件末尾填充大量无效但不影响解码的字节,瞬间放大体积,同时不改变图片实际像素数据:
- 原理:PNG/JPG等格式的解码器只会处理开头的有效数据,末尾垃圾数据会被忽略
- Kotlin代码示例:
val baseFile = cacheDir.resolve("base.png") // 先保存任意一张4096×4096的位图(推荐用方法1的无规律图) bitmap.compress(Bitmap.CompressFormat.PNG, 0, FileOutputStream(baseFile)) // 追加数据到目标大小(比如100MB) val targetSize = 100 * 1024 * 1024L val bytesToAdd = targetSize - baseFile.length() val outputStream = FileOutputStream(baseFile, true) // 追加模式 val buffer = ByteArray(1024 * 1024) // 1MB缓冲区 var remainingBytes = bytesToAdd while (remainingBytes > 0) { val writeSize = min(remainingBytes, buffer.size.toLong()).toInt() outputStream.write(buffer, 0, writeSize) remainingBytes -= writeSize } outputStream.close()
生成的文件大小精准可控,解码时仍会加载完整的4096×4096像素,触发OOM。
方法3:WebP无损压缩禁用优化
WebP的无损压缩支持更高的原始数据保留度,设置最高质量并禁用压缩优化,能生成接近原始位图大小的文件:
- Kotlin代码示例(需Android 10+,测试环境通常满足):
val outputStream = FileOutputStream(cacheDir.resolve("uncompressible.webp")) // WEBP_LOSSLESS模式+质量100,彻底禁用压缩优化 bitmap.compress(Bitmap.CompressFormat.WEBP_LOSSLESS, 100, outputStream) outputStream.close()
测试辅助技巧
- 若设备内存较大,可通过
adb shell setprop dalvik.vm.heapsize 64m手动限制应用堆内存,更容易触发OOM - 测试
sampleSize时,对比设置前后的内存占用(可通过Android Studio Profiler查看),确认是否有效避免内存溢出
内容的提问来源于stack exchange,提问作者fejd
相关产品推荐
相关产品推荐

