收藏
回答

画布多次绘制大图片(300kb)并调用 toDataURL 导致内存不足,可能存在内存泄漏?

框架类型 问题类型 API/组件名称 终端类型 微信版本 基础库版本
小程序 Bug wx.createOffScreenCanvas 微信iOS客户端 8.0.32 2.30.0

如题,在画布上绘制图片后通过 `toDataURL` 导出 base64 字符串,多次操作后会导致内存不足,闪退。

以我的手机为例:

型号: iPhone 12 mini,iOS 16.2

操作1:

  • 关闭‘使用缓存的离屏画布树’开关
  • 打开‘绘制大图片’开关
  • 点击‘添加绘图器’按钮多次(30次以上)
  • 小程序闪退提示内存不足或者微信闪退

操作2:

  • 打开‘使用缓存的离屏画布树’开关
  • 打开‘绘制大图片’开关
  • 点击‘添加绘图器’按钮多次(30次以上)
  • 小程序闪退提示内存不足或者微信闪退

操作3:

  • 打开‘使用缓存的离屏画布树’开关
  • 打开‘绘制大图片’开关
  • 点击‘添加绘图器’按钮多次(10次以上)
  • 点击‘绘制器重绘'按钮多次,使‘绘制次数’超过30次
  • 小程序闪退提示内存不足或者微信闪退

操作4:

  • 打开‘使用缓存的离屏画布树’开关
  • 关闭‘绘制大图片’开关
  • 点击‘要插入的绘图器数’,输入‘100’
  • 点击‘添加绘图器’按钮2次,使‘绘图器数量’为200
  • 点击‘绘制器重绘'按钮多次,使‘绘制次数’超过2000次
  • 小程序依旧正常

以上的几个操作主要控制的变量为‘离屏画布的数量’和‘绘制图片的大小’,可以发现当离屏画布增多或者绘制图片大(320kb)时,程序在有限的绘制次数后就会崩溃。而绘制图片相对小(90kb)时,即使绘制次数达到2000也不会出现崩溃。

个人认为值得怀疑的目标是 `offscreenCanvas.toDataURL` 、 `offscreenCanvas.createImage`、`offscreenCanvas.drawImage`,似乎这两个方法返回的对象都没有及时被 GC。

如果这确实是一个 Bug 但短期无法修复的话,有没有任何方法可能手动回这些内存呢?

最后一次编辑于  2023-02-05
回答关注问题邀请回答
收藏

4 个回答

  • 社区技术运营专员--许涛
    社区技术运营专员--许涛
    2023-02-06

    你好,经排查,drawImage 和 toDataURL 接口本身不存在内存泄漏问题。但对同一个 image 对象多次设置 src 会存在内存泄漏,建议避免这种用法,将在后面的版本中修复

    2023-02-06
    有用 1
    回复 3
    • KaygNas
      KaygNas
      2023-02-06
      多谢,老哥。
      顺便问一句,能帮我跳级到4级嘛?我下次发现 Bug 还来找你。🌚
      2023-02-06
      回复
    • KaygNas
      KaygNas
      2023-02-06
      我最初的版本是没有缓存 Image 对象和 OffscreenCanvas 对象的,也就不会对 Image 对象的 src 多次赋值,但也泄漏了,可以的话能稍微解释一下是如何泄漏的吗?
      2023-02-06
      回复
    • 社区技术运营专员--许涛
      社区技术运营专员--许涛
      2023-02-07回复KaygNas
      没有发现创建多个 image 和 canvas 存在泄漏问题,但创建多个大图片以及 canvas 对象对内存的占用较大,不推荐这种使用方式
      2023-02-07
      回复
  • 徐徐徐
    徐徐徐
    2023-02-04

    应该是重复创建了离屏canvas,每次点击都会执行wx.createOffscreenCanvas;

    const canvas = wx.createOffscreenCanvas({ type: '2d' }); 定义一次就行了;

    2023-02-04
    有用 1
    回复 3
    • KaygNas
      KaygNas
      2023-02-04
      在实际项目中做了这个优化,但是依然会闪退,只不过能操作更多吃了。
      期望的还是函数执行完后,在函数上下文中分配的内存都能够被释放。
      2023-02-04
      回复
    • 徐徐徐
      徐徐徐
      2023-02-04回复KaygNas
      2023-02-04
      1
      回复
    • KaygNas
      KaygNas
      2023-02-04回复徐徐徐
      能帮我邀请官方来解答一下吗?
      2023-02-04
      回复
  • KaygNas
    KaygNas
    2023-02-05

    补充一些可能关联的帖子:

    2023-02-05
    有用
    回复
  • 笑望长空
    笑望长空
    发表于小程序端
    2023-02-04

    页面加载时定义canvas一次,并保存ctx,在点击事件中调用ctx绘制

    2023-02-04
    有用
    回复 5
    • KaygNas
      KaygNas
      2023-02-04
      多谢,在实际项目中做了这个优化,但是依然会闪退,只不过能操作更多次了。
      能帮我邀请官方来解答一下吗?
      2023-02-04
      回复
    • 笑望长空
      笑望长空
      发表于小程序端
      2023-02-05回复KaygNas

      个人认为还是你写法上存在问题

      2023-02-05
      回复
    • KaygNas
      KaygNas
      2023-02-05回复笑望长空
      大佬,我更新了代码片段,加入了几种不同的重现操作,可以再帮我看看吗?
      2023-02-05
      回复
    • 笑望长空
      笑望长空
      发表于小程序端
      2023-02-05回复KaygNas

      canvas画布为什么要建那么多个?一个就够了,CTX绘制的内容会一直叠加,使用JS数组存储这个过程,重新绘制只需要清除画布即可

      2023-02-05
      回复
    • KaygNas
      KaygNas
      2023-02-05
      已经是只创建一个OffscreenCanvas、一个Image了,和最初的Demo完全不一样了。可以看看新的代码片段。
      2023-02-05
      回复
登录 后发表内容