Chrome V8系列--浅析Chrome V8引擎中的垃圾回收机制和内存泄露优化策略 (3)

清除对象后会造成堆内存出现碎片的情况,当碎片超过一定限制后会启动压缩算法。在压缩过程中,将活的对象像一端移动,直到所有对象都移动完成然后清理掉不需要的内存。

 

七、内存泄露和优化

7.1 什么是内存泄露?

存泄露是指程序中已分配的堆内存由于某种原因未释放或者无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统奔溃等后果。。

7.2 常见的内存泄露的场景

7.2.1 缓存

js开发时候喜欢用对象的键值来缓存函数的计算结果,但是缓存中存储的键越多,长期存活的对象就越多,导致垃圾回收在进行扫描和整理时,对这些对象做了很多无用功。

7.2.2 作用域未释放(闭包)

var leakArray = []; exports.leak = function () { leakArray.push("leak" + Math.random()); }

模块在编译执行后形成的作用域因为模块缓存的原因,不被释放,每次调用 leak 方法,都会导致局部变量 leakArray 不停增加且不被释放。

闭包可以维持函数内部变量驻留内存,使其得不到释放。

 

7.2.3 没有必要的全局变量

声明过多的全局变量,会导致变量常驻内存,要直到进程结束才能够释放内存。

 

7.2.4 无效的DOM引用

//dom still exist function click(){ // 但是 button 变量的引用仍然在内存当中。 const button = document.getElementById('button'); button.click(); } // 移除 button 元素 function removeBtn(){ document.body.removeChild(document.getElementById('button')); }

 

7.2.5 定时器未清除

// vue 的 mounted 或 react 的 componentDidMount componentDidMount() { setInterval(function () { // ...do something }, 1000) }

vue 或 react 的页面生命周期初始化时,定义了定时器,但是在离开页面后,未清除定时器,就会导致内存泄漏。

 

7.2.6 事件监听为空白

componentDidMount() { window.addEventListener("scroll", function () { // do something... }); }

在页面生命周期初始化时,绑定了事件监听器,但在离开页面后,未清除事件监听器,同样也会导致内存泄漏。

 

7.3 内存泄露优化

7.3.1 解除引用

确保占用最少的内存可以让页面获得更好的性能。而优化内存占用的最佳方式,就是为执行中的代码只保存必要的数据。一旦数据不再有用,最好通过将其值设置为 null 来释放其引用——这个做法叫做解除引用(dereferencing)

function createPerson(name){ var localPerson = new Object(); localPerson.name = name; return localPerson; } var globalPerson = createPerson("Nicholas"); // 手动解除 globalPerson 的引用 globalPerson = null;

解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收

 

7.3.2 提供手动清空变量的方法

var leakArray = []; exports.clear = function () { leakArray = []; }

 

7.3.3 其他方法

1、在业务不需要的用到的内部函数,可以重构到函数外,实现解除闭包。

2、避免创建过多的生命周期较长的对象,或者将对象分解成多个子对象。

3、避免过多使用闭包。

4、注意清除定时器和事件监听器。

5、nodejs中使用stream或buffer来操作大文件,不会受nodejs内存限制。

6、使用redis等外部工具来缓存数据。

 

八、总结

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjdwz.html