显存不会自动回收,必须手动调用 dispose() 或 gl.deleteTexture() 释放;否则纹理持续占用 VRAM 并引发镜像内存膨胀,最终导致 OOM 崩溃或卡顿。

频繁更改纹理却不调用 dispose(),会直接导致显存(VRAM)持续累积、无法释放,最终触发 OOM 崩溃或严重卡顿。这不是“慢泄漏”,而是显存资源被长期独占、系统内存同步镜像膨胀的双重挤压。
显存不会自动回收,必须手动释放
WebGL 纹理、Canvas 的 GPU 后备缓冲区,其生命周期不由 JavaScript 垃圾回收器(GC)管理——V8 只管 JS 对象引用,不管底层 GPU 资源。即使你把 texture 对象设为 null 或离开作用域,只要没调 gl.deleteTexture(textureID)(WebGL)或 texture.dispose()(Three.js 等封装库),GPU 显存就一直挂着。
- 每个
gl.createTexture()分配的显存块,在未 delete 前始终占用 VRAM,且不计入performance.memory的 JS 堆统计 - 浏览器 Blink 引擎可能为该纹理保留 CPU 端镜像缓冲(尤其在 Canvas 2D + WebGL 混合渲染时),造成系统内存同步上涨
- Android WebView 或低端设备上,显存碎片化更明显:旧纹理未删,新纹理又申请,很快触达 GPU 内存上限(如 128MB 限制)
反复 upload 导致显存翻倍式增长
每次调用 gl.texImage2D() 或 ctx.drawImage(canvas) 更新纹理内容,若目标纹理未被销毁,浏览器通常会:
用户要生成可打印的中文字帖/练习纸、导出多页 A4 PDF 报告,或把 SVG 设计稿零误差还原到 Canvas 时使用。本技能是「Canvas 内容工厂闭环」的总控,编排:网格渲染引擎(13 种教育网格+拼音标注) → 多页 PDF 导出(A4 合成) → SVG 精准复刻(坐标误差<0.001px)。触发词:生成字帖、练习纸、导出 PDF、SVG 转 Canvas、印刷级还原、A4 报告、米字格田字格。
- 复用原有纹理对象,但内部触发显存重分配(尤其图像尺寸变化时)
- 旧纹理数据未必立即清除,尤其当它还在某次 draw call 的引用链中(如绑定在 active texture unit)
- 若用 Canvas 作为纹理源(
gl.texImage2D(..., canvas)),Canvas 自身若也未清理(比如宽高反复重设),会额外拖垮 CPU 内存(见 4096×4096 显存镜像翻倍问题)
Three.js 等封装库的 dispose() 不是可选操作
像 Three.js 的 Texture、BufferGeometry、Material 都带 dispose() 方法,本质就是封装了对应的 WebGL 清理调用:
-
texture.dispose()→gl.deleteTexture(texture.id) -
material.dispose()→ 清理其关联的 shader、texture、attributes - 漏掉任意一个,对应显存就“永久驻留”,哪怕 JS 对象已被 GC 回收
- 特别注意:克隆纹理(
new Texture(...))或动态生成材质时,容易忘记 dispose 原始模板
混合渲染场景下更危险
Canvas 2D + WebGL 混合使用(如 UI 层用 Canvas,3D 场景用 WebGL)时,常见陷阱:
- 用
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas)每帧更新 HUD,但 canvas 没复用、texture 没 dispose - iOS 微信小程序中,
wxBindCanvasTexture绑定后,若 Canvas 内容重绘但未主动解绑或 dispose,纹理引用计数不降,显存锁死 - 离屏 Canvas(
offscreenCanvas)创建后未调transferToImageBitmap().close(),其 GPU 后备缓冲也会滞留
















