[3.8.7/3.8.8]ImageAsset无法释放,导致微信小游戏内存过高

构建微信小游戏时,同一个 ImageAsset 会通过 _textureSource 和 _mipmaps[0] 被 Texture2D 引用两次,但 _assignImage() 上传完成后只清理一次依赖和引用,导致 ImageAsset 引用计数残留为 1, 就算CLEANUP_IMAGE_CACHE为true也无法释放。
在微信小游戏中,Image 对象会缓存解码后的图片数据,导致内存过高。

而 Preview 中没有生成_textureSource这条额外的构建依赖,对应图片 UUID 在 Texture2D 依赖列表中只有一次,所以这个问题只在构建产物中明显出现。

是由3.8.7的这条改动引起的:https://github.com/cocos/cocos-engine/pull/18569

    Texture2D._textureSource → ImageAsset
    Texture2D._mipmaps[0]    → ImageAsset

资源加载阶段的 setProperties() 会遍历所有依赖,并为每条依赖执行一次:
depend.owner[depend.prop] = dependAsset.addRef();
所以同一个 ImageAsset 被 addRef() 两次。
而SimpleTexture._assignImage() 只查找并删除第一条匹配的 UUID:

if (macro.CLEANUP_IMAGE_CACHE) {
    const deps = dependUtil.getDeps(this._uuid);
    const index = deps.indexOf(image._uuid);
    if (index !== -1) {
        js.array.fastRemoveAt(deps, index);
        image.decRef();
    }
}

这里存在数量不对称:
setProperties(): addRef × 2
_assignImage(): decRef × 1
结果就是:ImageAsset.refCount: 2 → 1,引用计数始终无法归零。

临时修复方案:
修改 _assignImage() 的依赖清理逻辑:不再只删除第一条对应依赖,而是删除当前 Texture2D 依赖列表中该 ImageAsset UUID 的所有条目,并针对每条被删除的依赖调用一次 decRef()

if (macro.CLEANUP_IMAGE_CACHE) {
    const dependencies = assetManager.dependUtil.getDeps(this.uuid);
    let dependencyIndex = dependencies.indexOf(image.uuid);

    // 每删除一条依赖,平衡 setProperties() 中对应的一次 addRef()。
    while (dependencyIndex !== -1) {
        js.array.fastRemoveAt(dependencies, dependencyIndex);
        image.decRef();
        dependencyIndex = dependencies.indexOf(image.uuid);
    }
}
4赞

3.8 这种严重的内存问题,现在才暴露出来?难以想象啊都

1赞

387 改动导致的新 bug 好多,我都不知道那时候他们怎么审核 PR 的 :sweat_smile: 是不是因为快被收购了所以掉以轻心……