前端小知识点:JS垃圾回收机制
Posted 前端小歌谣
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端小知识点:JS垃圾回收机制相关的知识,希望对你有一定的参考价值。
目录
一、什么是垃圾回收
垃圾回收是一种自动的内存管理机制。当计算机上的动态内存不再需要时,就应该予以释放,以让出内存。直白点讲,就是程序是运行在内存里的,当声明一个变量、定义一个函数时都会占用内存。内存的容量是有限的,如果变量、函数等只有产生没有消亡的过程,那迟早内存有被完全占用的时候。这个时候,不仅自己的程序无法正常运行,连其他程序也会受到影响。好比生物只有出生没有死亡,地球总有被撑爆的一天。所以,在计算机中,我们需要垃圾回收。需要注意的是,定义中的“自动”的意思是语言可以帮助我们回收内存垃圾,但并不代表我们不用关心内存管理,如果操作不当,javascript 中依旧会出现内存溢出的情况。
二.垃圾回收机制原理
垃圾回收基于两个原理:
1、考虑某个变量或对象在未来的程序运行中将不会被访问
2、向这些对象要求归还内存
而这两个原理中,最主要的也是最艰难的部分就是找到“所分配的内存确实已经不再需要了”。
三、垃圾回收方法
现在各大浏览器通常用采用的垃圾回收有两种方法:标记清除、引用计数。
3.1 引用计数
这是最初级的垃圾回收算法(老牌浏览器使用:IE)。引用计数的策略是跟踪记录每个值被使用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,这个值得引用次数就加一,如果该变量的值变成了另一个,则这个值得引用次数就减一,当这个值的引用次数为0的时候,说明没有变量在使用,这个值无法访问。由此可以将其占用的空间回收,这些垃圾回收器就会在运行时清理掉引用次数为0的值占用的空间,但这种方法容易引起内存泄漏,因为这种方式没有解决循环引用的问题,所以不建议使用!
function fun4(){
var obj = {}//引用类型变量,c的引用计数为0
var o = obj; //obj被o引用,obj的引用计数为1
var m = obj; //obj被m引用,obj的引用计数为2
o = {} //o不再引用obj,obj的引用计数减为1
m = null //m不再引用obj,obj的引用计数减为0
}
但是引用计数存在一些问题:循环引用
function fun5(){
var f = {};
var g = {};
f.userName = g;
g.userName = f;
//由于f和g互相引用,计数永远不可能为0
}
3.2 标记清除
这是javascript中最常用的垃圾回收方式。当变量进入执行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”。
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
function fun3(){
var a = 1;
var b = 2;
//函数执行时,ab分别被标记,进入环境
}
fun3() 函数执行结束,ab被标记 离开环境 ,被回收
但是也要注意
function fun1(){
var obj = {}
}
function fun2(){
var obj = {}
return obj;
}
var a = fun1();
var b = fun2();
fun1 执行时为 obj 分配了一块内存,但是随着函数执行结束,obj占用的空间也就被释放了
fun2 执行时,也为 obj 分配了内存,但是由于 obj
最终被返回赋值给了 b 导致其依然被使用,所以 fun2 中的 obj 占用的内存不会被释放
-
内存常见内存泄露以及解决方法
-
4.1 全局变量:
function foo() {
this.bar2 = '默认绑定this指向全局' // 全局变量=> window.bar2
bar = '全局变量'; // 没有声明变量 实际上是全局变量=>window.bar
}
foo();
解决方法:在函数内使用严格模式==》严格模式禁止this关键字指向全局对象
function foo() {
"use strict";
this.bar2 = "严格模式下this指向undefined";
bar = "报错";
}
foo();
4.2 定时器和回调函数
当不需要setInterval或者setTimeout时,定时器没有被clear,定时器的回调
函数以及内部依赖的变量都不能被回收,造成内存泄漏。
var someResource = getData();
setInterval(function() {
var node = document.getElementById('Node');
if(node) {
node.innerhtml = JSON.stringify(someResource));
// 定时器也没有清除
}
// node、someResource 存储了大量数据 无法回收
}, 1000);
解决方法: 在定时器完成工作的时候,手动清除定时器。
4.3 闭包
闭包可以维持函数内局部变量,使其得不到释放,造成内存泄漏。
function bindEvent() {
var obj = document.createElement("XXX");
var unused = function () {
console.log(obj,'闭包内引用obj obj不会被释放');
};
// obj = null;
}
解决方法:手动解除引用,obj = null。
4.4 没有清理DOM元素引用:
var refA = document.getElementById('refA');
document.body.removeChild(refA); // dom删除了
console.log(refA, "refA"); // 但是还存在引用 能console出整个div 没有被回收
解决办法:refA = null;
以上是关于前端小知识点:JS垃圾回收机制的主要内容,如果未能解决你的问题,请参考以下文章