核心是控制Phaser参与者生命周期以实现可预测复用与回收:预分配池复用Image/Canvas、禁用自动缓存、强制销毁纹理、直连WebGL资源、隔离流上下文,并加入节流监控兜底机制。

核心是不让 Phaser 参与者(如图像、纹理、容器)在格式转换流中无节制创建,同时切断它们与 GC 的强绑定关系。关键不在“阻止增加”,而在“让增加可预测、可复用、可回收”。
控制参与者生命周期:只复用,不新建
多模态格式转换(如 WebP → PNG → Canvas → Texture)常伴随大量中间图像对象生成。Phaser 中每调用一次 this.textures.addCanvas() 或 this.add.image(),若未显式管理,就会产生一个新实例并长期驻留渲染树或纹理缓存中。
- 所有图像/纹理操作统一走预分配池:在
create()阶段预先创建固定数量的Phaser.GameObjects.Image和离屏HTMLCanvasElement,用setTexture()动态切换内容,而非反复add.image() - 禁用自动纹理缓存:对临时转换用的 canvas,创建时加
{ skipCache: true }参数,避免被 Phaser.TextureManager 拦截并长期持有 - 每次转换完成后立即调用
texture.destroy(true)(第二个参数true强制释放底层 WebGL 资源),再手动canvas.remove()或canvas.width = canvas.height = 0归零引用
隔离流处理上下文:避免跨帧持有缓冲区
格式转换流(如 ReadableStream.pipeThrough() + TransformStream)容易把 Uint8Array 或 ImageBitmap 持有到下一个事件循环甚至 await 后,导致 Phaser 相关对象无法及时释放。
- 确保每个 chunk 解析后立即转为
Phaser.Textures.CanvasTexture,且该 texture 的 canvas 来自预分配池(非 new Canvas()) - 禁止将转换中的
ImageBitmap或OffscreenCanvas传入scene.children.add();先转成Phaser.Textures.Texture再挂载,挂载后立刻丢弃原始 bitmap 引用 - 在
TransformStream.transform()回调内完成全部解析+贴图+销毁链路,不 await 外部异步逻辑,防止 buffer 被闭包捕获
绕过 Phaser 默认纹理管理:直连 WebGL 资源
Phaser 默认的 TextureManager 会为每个 texture 维护元数据、监听器、引用计数等,增加 GC 压力。对高频转换场景,应降级使用底层资源控制。
- 用
scene.sys.textures.glTexture获取原生 WebGLTexture 对象,通过gl.texImage2D()直接更新像素,跳过 Phaser 封装层 - 配合
OffscreenCanvas.getContext('2d')+transferToImageBitmap(),再用WebGLRenderingContext.texImage2D()上传,全程不经过Phaser.Textures.Texture构造 - 手动维护一个
Map<string, WebGLTexture>映射表替代 TextureManager,按需 bind/unbind,避免自动注册和监听器累积
监控与兜底:主动触发清理节奏
即使做了上述控制,流速突增仍可能导致瞬时对象堆积。需加入轻量级节流与强制回收机制。
- 用
scene.sys.game.loop.timeStep计算每秒处理帧数,当连续 3 帧超过阈值(如 >15 个新 texture),自动暂停流读取,执行scene.sys.textures.removeAll()清空非活跃纹理 - 在
scene.update()开头检查scene.children.list.filter(c => c.texture?.key?.startsWith('temp_')).length > 10,超限时批量调用c.destroy() - 启用 Chrome DevTools 的 Memory > Allocation instrumentation on timeline,过滤 “Phaser.” 关键字,定位哪类对象泄漏最严重,针对性加固销毁路径

















