以前接触的js的内存管理方面的内容一直比较零散,最近在这一块作了一些系统的学习.学习过程当中的一些总结在这里分享给你们.欢迎批评指正,共同窗习,共同进步.javascript
在一部分语言中是提供了内存管理的接口的,例如C语言中的 malloc()
和 free()
; 而在 JavaScript
中会自动进行内存的分配和回收的,由于自动这两个字,就让不少的开发者认为咱们是不须要去关心内存方面的问题,固然,这是一种错误的见解.关注内存的管理,避免内存的泄漏也是性能优化重要的一项.前端
Javascript
变量的生命周期要分开来看,对于全局变量,他的生命周期会持续到页面关闭(这就涉及到了后面要总结的内存泄漏的一种方式).而对于局部变量,在所在的函数的代码执行以后,局部变量的生命周期结束,他所占用的内存会经过垃圾回收机制释放(即垃圾回收).java
垃圾回收一般有两种方式来实现:node
这种算法在MDN
文档中被称为最"天真"的垃圾回收算法;核心原理是: 判断一个对象是否要被回收就是要看是否还有引用指向它,若是是"零引用",那么就回收.说这种算法天真,是由于它存在着较为严重的缺陷---循环引用:git
function f(){
var o = {};
var o2 = {};
o.a = o2; // o 引用 o2
o2.a = o; // o2 引用 o
return "azerty";
}
f();
复制代码
首先要注意咱们是在函数做用域中讨论的这个问题,而不是全局环境中.老版本的IE中的非JavaScript
原生对象如 DOM
和 BOM
对象就采用的这种策略.下面这种状况下就会出现内存泄漏:github
var el =document.getElementById("some_element");
var Obj =new Object();
myObj.el = el;
el.someObject = Obj;
复制代码
固然咱们能够在不用的时候手动释放:算法
myObj.el = null;
el.someObject = null;
复制代码
这个算法把“对象是否再也不须要”简化定义为“对象是否能够得到”.chrome
这个算法假定有一个根(root)的对象;在 Javascript
里,根是全局对象,对应于浏览器环境的 window
,node
环境的 global
.垃圾回收器将按期从根开始,找全部从根开始引用的对象,而后找这些对象引用的对象……从根开始,垃圾回收器将找到全部能够得到的对象和收集全部不能得到的对象.浏览器
这个算法相对于引用计数的优点在于,“有零引用的对象”老是不可得到的,可是相反却不必定,参考“循环引用”.性能优化
从2012年起,全部现代浏览器都使用了标记-清除垃圾回收算法,都是在此基础上进行优化.全部对JavaScript垃圾回收算法的改进都是基于标记-清除算法的改进,并无改进标记-清除算法自己和它对“对象是否再也不须要”的简化定义.
限制: 那些没法从根对象查询到的对象都将被清除 固然,在咱们的开发实践中不多遇到这种状况,这也是咱们忽略内存管理的缘由之一.
function a(){
b=2
console.log('b没有被声明!')
}
复制代码
b
没被声明,会变成一个全局变量,在页面关闭以前不会被释放.使用严格模式能够避免.
var leaks = (function(){
var leak = 'xxxxxx';// 闭包中引用,不会被回收
return function(){
console.log(leak);
}
})()
复制代码
固然有时候咱们是故意让这个变量保存在内存中的,可是要避免无心的时候形成的内存泄漏.
DOM
节点时候忘记移除暂存的值有时候出于优化性能的目的,咱们会用一个变量暂存 节点
,接下来使用的时候就不用再从 DOM
中去获取.可是在移除 DOM
节点的时候却忘记了解除暂存的变量对 DOM
节点的引用,也会形成内存泄漏
var element = {
image: document.getElementById('image'),
button: document.getElementById('button')
};
document.body.removeChild(document.getElementById('image'));
// 若是element没有被回收,这里移除了 image 节点也是没用的,image 节点依然留存在内存中.
复制代码
与此相似情景还有: DOM
节点绑定了事件, 可是在移除的时候没有解除事件绑定,那么仅仅移除 DOM
节点也是没用的
var someResource = getData();
setInterval(function() {
var node = document.getElementById('Node');
if(node) {
node.innerHTML = JSON.stringify(someResource));
}
}, 1000);
复制代码
若是没有清除定时器,那么 someResource
就不会被释放,若是恰好它又占用了较大内存,就会引起性能问题. 再提一下 setTimeout
,它计时结束后它的回调里面引用的对象占用的内存是能够被回收的. 固然有些场景 setTimeout
的计时可能很长, 这样的状况下也是须要归入考虑的.
老版本的在 Timeline
中查看, 新版本的在 performance
中查看:
步骤:
Performance
Screenshots
和 memory
图中 Heap
对应的部分就能够看到内存在周期性的回落也能够看到垃圾回收的周期,若是垃圾回收以后的最低值(咱们称为min),min在不断上涨,那么确定是有较为严重的内存泄漏问题.
关于工具的使用暂时在这里浅尝辄止了,后面再深刻的学习了开发者工具方方面面的使用再来和你们分享.
参考文档:
本文发布于薄荷前端周刊,欢迎Watch & Star ★,转载请注明出处。