36.js的垃圾回收与内存泄漏

61 阅读3分钟

垃圾回收

我们使用程序时,我们是在内存中运行的,当我们创建变量,函数的时候,他就会占用内存空间,我们不使用这些变量或者函数的时候我们就应该清除他,不然内存占用就会越来越大,最后直至内存崩溃
js的垃圾回收就是找出不会再使用的变量,释放其占用的内存空间\

标记清除(mark-and-sweep)

js中最常用的垃圾回收方式就是标记清除。当变量进入环境时,例如,在一个函数中声明一个变量,就将这个变量标记为"进入环境",从逻辑上讲,永远不能释放进入环境变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为"离开环境"

function test(){ var a = 10; //被标记"进入环境" 
var b = "hello"; //被标记"进入环境" } 
test(); //执行完毕后之后,a和b又被标记"离开环境",被回收

引用计数(reference counting)

引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1,如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值的引用的变量又取得了另外一个值,则这个值的引用次数减1,当这个值的引用次数为0时,则说明没有办法再访问这个值了,因此就可以将其占用的内存空间回收回来。

let aa = [] // 数组[]引用1次 
let bb = aa // 数组引用2次 
bb = null // 释放内存,引用还剩下1次,即变量aa的引用还存在

IE9以下还在使用引用计数,当对象循环引用时,引用次数无法标记为0,就会导致无法被回收。其他浏览器废弃使用;

js的内存泄漏

内存泄漏是应用程序过去使用,但不再需要的尚未返回到操作系统或可用内存池的内存片段。由于没有被释放而导致的,它将可能引起程序的卡顿和崩溃; 我们在chrome中可以看到内存的使用情况 检查-memory

image.png

意外的全局变量

一个未声明变量的引用会在全局对象中创建一个新的变量。在浏览器的环境下,全局对象就是window

function foo(arg) {
    bar = "this is a hidden global variable";
}

dom泄漏

  • 浏览器中DOM和js采用的是不一样的引擎,DOM采用的是渲染引擎,而js采用的是v8引擎,所以在用js操作DOM时会比较耗费性能,因为他们需要桥来链接他们。为了减少DOM的操作,我们一般将常用的DOM;
  • 我们会采用变量引用的方式会将其缓存在当前环境。如果在进行一些删除、更新操作之后,可能会忘记释放已经缓存的DOM;
var elements = { 
    buttondocument.getElementById('button'), 
    imagedocument.getElementById('image') 
}; 
function doStuff() { 
    elements.image.src = 'http://test.png'; 
} 
function removeImage() { 
    // image 元素是body的直接子元素。 
    document.body.removeChild(document.getElementById('image')); 
    // 我们仍然可以在全局元素对象中引用button。换句话说,button元素仍在内存中,无法由GC收集 

闭包

闭包可以使变量常驻内存,但如果使用不当就会在成内存泄漏

var theThing = null;
var replaceThing = function () {
  var originalThing = theThing;
  var unused = function () {
    if (originalThing)
      console.log("hi");
  };
  theThing = {
    longStr: new Array(1000000).join('*'),
    someMethod: function () {
      console.log(someMessage);
    }
  };
};
setInterval(replaceThing, 1000);

定时器或者回调

var someResouce=getData();  
setInterval(function(){  
    var node=document.getElementById('Node');  
    if(node){  
        node.innerHTML=JSON.stringify(someResouce)  
    }  
},1000)