记录一次threejs内存泄露问题排查过程

本文讲述了在使用three.js进行地图编辑时,组件反复挂载/销毁导致页面卡顿和内存增长的问题。作者通过ChromeDevTools分析发现DOMNodes和JSEventListeners未正确清理,从而定位到内存泄露。最后,作者给出了清除定时器、事件监听和three.js控制器中事件的方法,成功解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:

一个有关地图编辑的使用threejs的这样的组件,在多次挂载销毁后,页面开始卡顿。

问题排查:

1. 首先在chrome dev tool中打开performance monitor面板,观察 JS head size、DOME Nodes、Js event listeners数据是否呈现增长趋势

观察了一段时间,发现JS head size并没有明显的增长,但是DOM Nodes、Js event listeners随着每次组件的销毁、组件的重新挂载一直呈现增加的趋势。

2. 在chrome dev tool中打开performance进行性能分析

在performance面板中我们录制大概60s性能分析

查看结果

首先我们看一下JS head size,观察到在1分钟的组件不断销毁和挂载的过程中,是收敛的,组件挂载是增长,组件卸载时释放,是正常现象。

其次我观察到DOM Nodes、Js event listeners在1分钟的组件不断销毁和挂载的过程中,呈现阶梯式的增长,且增长的幅度几乎一致,如下图。

初步分析是在组件卸载时有事件监听没有销毁。

3. 在chrome dev tool中打开memory面板中进行深层次的分析

在memory面板中,多录制几个快照

我发现heap size是不断增长的,确认是存在内存泄露的问题的。

现在我选取Snapshot5和Snapshot4进行对比,看一下,增长的是什么

注意我框出来的地方。重点看delta哪些在增长。其中 compiled code这种不用管。这是编辑好的代码。

我们看到 HTMLDivElement、EventListener、ResizeObserver、等这些的增长,都能看出来我们的分析是对的,确实很多监听事件没有清除。

接下来我们去清除这些事件,再次捕捉快照看一下对比。

解决问题

1. 确定 setTimeout、setInterval、requestAnimationFrame等在组件销毁时清除,requestAnimationFrame很容易遗漏

2. 确认 addEventListener的事件在组件销毁时移除了。

这里需要注意一下,最好通过  document.removeEventListener(eventname,fn)的方式去清除

我之前通过document.onclick = null的方式去清除,发现还是会出现内存泄露的问题。

3. threejs引入的dragControls、orbitControls、还有自己封装的controls等在组件销毁时,记得销毁这些控制器中的事件监听。比如dragControls提供了方法 deactivate 方法去清除监听。

4. 在组件销毁时确认清除了 ResizeObserver

确保了这些问题都处理后,再次用performance性能分析60s,查看结果

我们看到DOM Nodes、Js event listeners在组件销户和挂载过程中是收敛的,不会再呈现阶梯式增长。问题得到解决。

再次去memory面板中查看新的快照

我们看到清除了这些事件监听后,heap size不再增长了,我们再具体对比一下Snapshot5和Snapshot4

之前的那些增长项,都为0了。至此问题解决。

还有一个常识时,在组件销毁时,记得把threejs scene中的所以object清除了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值