记一次three.js内存泄漏排查

2,293 阅读2分钟

记一次three.js内存泄漏排查

开场白

这里就不提chrome的devtools工具的memory,因为内存泄漏问题是肯定存在的,技术支持同事的机子内存都吃满无法释放的,严重影响软件运行。

问题分析

  • setTimeout Interval 未清除
  • addEventListerne 未remove
  • dom元素被引入,导致dom节点无法销毁 const idDOM = document.getElementById('id')
  • 全局变量 window.xxxx
  • 闭包
  • console.log 输入的对象被引用,导致无法释放

在vue文档里面也有指导,需要在beforeDestroy周期内做释放

cn.vuejs.org/v2/cookbook…

我们在再看看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(); 
	
}