垃圾回收机制
- 浏览器的 Javascript 具有自动垃圾回收机制,执行环境会负责管理代码执行过程中使用的内存。
- 原理是:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,释放其内存。但是这个过程不是实时的,因为其开销比较大并且GC时停止响应其他操作,所以垃圾回收器会按照固定的时间间隔周期性的执行。
只有函数内的变量才可能被回收
- 垃圾回收机制有两种:
- 标记清除 下面代码:【最常用】
-
function test(){ var a = 10 ; // 被标记 ,进入环境 var b = 20 ; // 被标记 ,进入环境 } test(); // 执行完毕 之后 a、b又被标离开环境,被回收。
js中最常用的垃圾回收方式就是标记清除。当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
- 引用计数
引用计数的含义是跟踪记录每个值被引用的次数。
当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。
如果同一个值又被赋给另一个变量,则该值的引用次数加 1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减 1。
当这个值的引用次数变成 0 时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为 0 的值所占用的内存。
function test() {
var a = {}; // a指向对象的引用次数为1
var b = a; // a指向对象的引用次数加1,为2
var c = a; // a指向对象的引用次数再加1,为3
var b = {}; // a指向对象的引用次数减1,为2
}
-
什么是内存泄漏?
-
程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。
对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃。
不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。
-
内存泄漏分为Vue中的内存泄漏和js中的内存泄漏
-
Vue 中的内存泄漏问题
1.如果在mounted/created钩子中使用 JS 绑定了DOM/BOM对象中的事件,需要在 beforeDestroy中做对应解绑处理;
2.如果在 mounted/created钩子中使用了第三方库初始化,需要在 beforeDestroy中做对应销毁处理(一般用不到,因为很多时候都是直接全局 Vue.use);
3.如果组件中使用了 setInterval,需要在 beforeDestroy中做对应销毁处理;
mounted() {
const box = document.getElementById('time-line')
this.width = box.offsetWidth
this.resizefun = () => {
this.width = box.offsetWidth
}
window.addEventListener('resize', this.resizefun)
},
beforeDestroy() {
window.removeEventListener('resize', this.resizefun)
this.resizefun = null
}
-
js中的内存泄漏
- 1.循环引用
一个DOM对象被一个Javascript对象引用,与此同时又引用同一个或其它的Javascript对象,这个DOM对象可能会引发内存泄露。这个DOM对象的引用将不会在脚本停止的时候被垃圾回收器回收。要想破坏循环引用,引用DOM元素的对象或DOM对象的引用需要被赋值为null。
- 2.闭包
在闭包中引入闭包外部的变量时,当闭包结束时此对象无法被垃圾回收
- 3.DOM泄漏
当原有的COM被移除时,子结点引用没有被移除则无法回收。
var select = document.querySelector;
var treeRef = select('#tree');
//在COM树中leafRef是treeFre的一个子结点
var leafRef = select('#leaf');
var body = select('body');
body.removeChild(treeRef);
//#tree不能被回收入,因为treeRef还在
//解决方法:
treeRef = null;
//tree还不能被回收,因为叶子结果leafRef还在
leafRef = null;
- 4.定时器、计时器泄漏(也是常见的内存泄漏的地方)
for (var i = 0; i < 90000; i++) {
var buggyObject = {
callAgain: function() {
var ref = this;
var val = setTimeout(function() {
ref.callAgain();
}, 90000);
}
}
buggyObject.callAgain();
//虽然你想回收但是timer还在
buggyObject = null;
}