记一次three.js内存泄漏排查
开场白
这里就不提chrome的devtools工具的memory,因为内存泄漏问题是肯定存在的,技术支持同事的机子内存都吃满无法释放的,严重影响软件运行。
问题分析
- setTimeout Interval 未清除
- addEventListerne 未remove
- dom元素被引入,导致dom节点无法销毁 const idDOM = document.getElementById('id')
- 全局变量 window.xxxx
- 闭包
- console.log 输入的对象被引用,导致无法释放
在vue文档里面也有指导,需要在beforeDestroy周期内做释放
我们在再看看three.js的文档 里面有章叫 # 如何废置对象(How to dispose of objects)
从这里我们可以知道,下面的对象都需要手动释放,它们提供了dispose() 方法以用于移除内部事件监听器或渲染目标
- 几何体 geometry
- 材质 matertial
- 纹理 texture
- 渲染目标 WebGLRenderTarget
- 场景 Scenes
问题处理
做new 上面的对象操作时,收藏记录其实例,退出时统一释放。
WebGLRenderer.info —— 渲染器中的一个特殊属性,具有一系列关于显存和渲染过程的统计信息。 除此之外,它还告诉你有多少纹理、几何体和着色器程序在内部存储。 如果你在你的应用程序中注意到了性能问题,一个较好的方法便是调试该属性,以便轻松识别内存泄漏。
上面是文档原话,通过它我们就可以调试到有多少纹理、几何体和着色器未释放!!
// 部分代码片段
function clearScene()
{
//清除场景,释放资源
//清除texture
for(var key in graymaps)
{
if(graymaps[key].dispose)
graymaps[key].dispose();
}
for(var key in hotmaps)
{
if(hotmaps[key].dispose)
hotmaps[key].dispose();
}
//清除geometry和material
//disposeObj(scene);
disposeObj(bldg);
disposeObj(pickingScene);
}
function disposeObj(obj)
{
if(!obj)
return;
if(obj.children)
{
for(let i=obj.children.length-1;i>=0;--i)
disposeObj(obj.children[i]);
}
if(obj.geometry)
obj.geometry.dispose();
if(obj.material) {
obj.material.dispose();
// 这段是这次内存泄漏的问题点,material里面的texture未处理
obj.material.map && obj.material.map.dispose();
}
obj.removeFromParent();
}