# 应用侧大图加载、图片编辑及长图预览引发OOM崩溃的优化方案

#### 问题现象

应用侧保存分辨率40320x25200大图到系统相册无法正常加载，且无法正常使用图片解码，如下图所示。

#### 背景知识

正常操作应用，观察运行过程中的应用内存变化情况。当在一段时间内应用内存没有明显增加或者在内存上涨后又逐渐回落至正常水平，则基本可以排除应用存在内存问题；反之，在一段时间内不断上涨且无回落或者内存占用明显增长超出预期，那么则可初步判断应用可能存在内存问题。可参考ArkTS内存泄漏分析。

#### 问题定位

测试使用代码如下：

```
async createPixel() {
  const resourceManager = this.getUIContext().getHostContext()?.resourceManager;
  const imageData = await resourceManager!.getMediaContent($r('app.media.startIcon').id);
  let arrayBuffer = imageData.buffer;
  const imageSource = image.createImageSource(arrayBuffer);
  console.info('createImageSource success')
  let imageInfo = imageSource.getImageInfoSync(0);
  let width = imageInfo.size.width;
  let height = imageInfo.size.height;
  const opts: image.DecodingOptions = {
    editable: true,
    desiredSize:{width:width,height:height},
    desiredPixelFormat: image.PixelMapFormat.BGRA_8888
  };
  let pixel = await imageSource.createPixelMap(opts);
  console.info('createPixelMap success')
  const imagePackerApi: image.ImagePacker = image.createImagePacker()
  let packOpts: image.PackingOption = {
    format:'image/jpeg',
    quality:100
  }
  try{
    imagePackerApi.packToData(pixel,packOpts).then(()=>{
      console.info('imagePacking success')
    })
  }catch (err){
    console.error('imagePacking failed',err)
  }
  console.info('imagePacking complete')
}
```

如下图所示：

可以看到使用超大图解码后，Heap存在明显上涨且长时间无回落。查询日志相关信息，通过日志发现尽管图片解码实例创建成功，但后续创建PixelMap以后的程序并未顺利执行，日志打印如下所示。

#### 分析结论

当图片分辨率过大（像素数超过4亿）时，此时解码占用内存高，触发严重的整机性能问题。图片分辨率降低后可以在图库中正常显示且解码正常。

#### 修改建议

HarmonyOS的图片解码对图片分辨率及文件占用的空间有限制，单张图片的文件占用空间大小不能超过2G，单个应用运行内存占用达到4G会触发整机性能问题。建议在图片解码前将图片压缩到指定大小，既可展示图片，又可以保证系统的稳定运行。正常日志打印效果如下：

针对大图加载、图片编辑及长图预览场景，参考图片区域解码与下采样指导和图片解码内存优化。

#### 常见FAQ

Q：超大图加载会非常耗内存，以至于卡顿卡死等情况，有什么优化的方案？

A：解码参数DecodingOptions有两个属性desiredRegion和desiredSize可以控制解码的区域以及输出的大小，同时传递两个属性需进一步传入cropAndScaleStrategy参数指定缩放与裁剪的先后顺序，推荐设置CROP\_FIRST。

Q：图片编辑功能中多次解码产生多个PixelMap导致内存叠加，如何优化？

A：编辑链路只保留一份当前工作PixelMap，旧的PixelMap和ImageSource用完后及时调用release()释放，并确认相关异步操作结束后再释放。不要让原图PixelMap、预览PixelMap、编辑PixelMap同时常驻。

Q：长图预览（高度超过10000px）加载时崩溃，如何处理？

A：不要一次性将完整大图交给Image组件加载，建议按可视区域分页或切片，用DecodingOptions的desiredRegion属性解码当前窗口附近的区域。