显存泄漏与内存泄漏不同:前者指GPU资源未释放导致显存持续占用,后者指堆内存分配后未释放;Chrome Memory面板不显示显存,需通过chrome://gpu查看Allocated/Peak usage及Problems Detected,并检查WebGL上下文销毁、纹理缓冲清理等。

显存泄漏和内存泄漏不是一回事
Chrome 的 Memory 面板只看 JS 堆和 DOM,完全不反映 GPU 显存(GPU memory / GPU memory buffers)。显存泄漏在 DevTools 里没有专用面板,强行用堆快照查只会漏掉真正的问题源头。显存占用飙升但 JS Heap 稳定,是典型信号——这时候该切到 chrome://gpu 和 chrome://system 看底层指标,而不是反复拍堆快照。
chrome://gpu 是第一个必查页
直接在地址栏输入 chrome://gpu,重点扫三块内容:
-
Graphics Feature Status区域确认Canvas、WebGL、Rasterization是否全为enabled;若某项显示disabled或software only,说明渲染已降级到 CPU,后续看到的“显存高”其实是内存误报 -
Driver Information下的GPU Memory Information表格,关注Allocated和Peak usage两列——这是真实显存分配量,单位 MB,持续上涨且不回落就是泄漏迹象 - 页面底部的
Problems Detected列表,如出现GPU process crashed或Texture upload failed,基本可锁定 WebGL 资源未释放或纹理尺寸越界
WebGL 上下文未销毁是最常见泄漏点
Three.js、Cesium、Babylon.js 等库创建的 WebGLRenderingContext 实例,一旦被全局变量、闭包或事件监听器意外持有,就会导致整个上下文及其所有纹理、缓冲区无法释放。典型表现是:切换路由后 chrome://gpu 显存不降,但 Performance 面板里 JS Heap 正常回收。
- 检查是否手动调用了
gl.getExtension('WEBGL_lose_context').loseContext()或canvas.getContext('webgl').loseContext()—— 这只是模拟丢失,不是销毁 - 确认是否执行了
gl.deleteTexture()、gl.deleteBuffer()、gl.deleteProgram()等清理动作,而非仅移除 DOM 元素 - Cesium 场景中,
viewer.destroy()必须调用,且不能在异步回调里延迟执行;否则viewer.scene.globe等内部纹理对象仍被引用
纹理上传未节制会快速耗尽显存
显存泄漏往往不是“一直不释放”,而是“反复申请却不复用”。比如每帧都用 gl.texImage2D() 上传新纹理,却没做尺寸校验或缓存复用:
- 避免动态生成超大纹理:单张 > 4096×4096 的 PNG/JPEG 在部分集成显卡上会触发显存碎片,建议预缩放到 2048×2048 并启用
gl.generateMipmap() - 禁用
gl.UNPACK_FLIP_Y_WEBGL和gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL等非必要像素操作,它们会在上传时额外分配显存做转换 - 用
chrome://tracing录制 WebGL 调用栈:勾选gpu和blink.graphics分类,搜索TexImage2D调用频次——如果每秒上百次且无对应DeleteTexture,就是泄漏铁证
显存不像 JS 内存有 GC 机制兜底,它靠开发者显式释放。哪怕只漏一个 1024×1024 的 RGBA 纹理(约 4MB),在长周期运行的可视化应用里几小时就能吃掉 1GB 以上显存。别依赖“浏览器自己会清”,得盯住 chrome://gpu 的数字,再顺藤摸到 WebGL 调用链里那个没被删掉的 texture 对象。

















