js垃圾回收

内存生命周期

  • 分配你所须要的内存
  • 使用分配到的内存(读、写)
  • 不须要时将其释放\归还

全部语言第二部分都是明确的.第一和第三部分在底层语言中是明确的,但在像 JavaScript 这些高级语言中,嵌入了'垃圾回收器',根据 Wiki 的定义,垃圾回收是一种自动的内存管理机制,用来追踪不用的内存并自动释放.javascript

JavaScript 的内存分配

值的初始化

var n = 123; // 给数值变量分配内存
var s = "azerty"; // 给字符串分配内存

var o = {
  a: 1,
  b: null
}; // 给对象及其包含的值分配内存

// 给数组及其包含的值分配内存(就像对象同样)
var a = [1, null, "abra"];

function f(a){
  return a + 2;
} // 给函数(可调用的对象)分配内存

// 函数表达式也能分配一个对象
someElement.addEventListener('click', function(){
  someElement.style.backgroundColor = 'blue';
}, false);

经过函数调用分配内存

有些函数调用结果是分配对象内存:html

var d = new Date(); // 分配一个 Date 对象

var e = document.createElement('div'); // 分配一个 DOM 元素

有些方法分配新变量或者新对象:java

var s = "azerty";
var s2 = s.substr(0, 3); // s2 是一个新的字符串
// 由于字符串是不变量,
// JavaScript 可能决定不分配内存,
// 只是存储了 [0-3] 的范围.

var a = ["ouais ouais", "nan nan"];
var a2 = ["generation", "nan nan"];
var a3 = a.concat(a2);
// 新数组有四个元素,是 a 链接 a2 的结果

使用值

使用值的过程其实是对分配内存进行读取与写入的操做.读取与写入多是写入一个变量或者一个对象的属性值,甚至传递函数的参数.算法

垃圾回收

程序是运行在内存里的,当声明一个变量、定义一个函数时都会占用内存.内存的容量是有限的,若是变量、函数等只有产生没有消亡的过程,那早晚内存有被彻底占用的时候.这个时候,不只本身的程序没法正常运行,连其余程序也会受到影响.因此,在计算机中,咱们须要垃圾回收.须要注意的是,定义中的“自动”的意思是语言能够帮助咱们回收内存垃圾,但并不表明咱们不用关心内存管理,若是操做失当,JavaScript 中依旧会出现内存溢出的状况.segmentfault

当一些变量不在须要的时候,javascript 会对该这些变量占用的内存进行释放,而'哪些被分配的内存确实已经再也不须要了'是一个难实现的任务.在基础语言中,每每要求开发人员来肯定在程序中那一块内存不在须要它以后释放它.而高级语言解释器中嵌入了'垃圾回收器',它的主要工做是跟踪内存的分配和使用,以便当分配的内存再也不使用时,自动释放它.垃圾回收实现只能有限制的解决通常问题,由于要知道是否仍然须要某块内存是没法断定的(没法经过某种算法解决).数组

引用

垃圾回收算法主要依赖于引用的概念.在内存管理的环境中,一个对象若是有访问另外一个对象的权限(隐式或者显式),叫作一个对象引用另外一个对象.例如,一个 Javascript 对象具备对它原型的引用(隐式引用)和对它属性的引用(显式引用).浏览器

在这里,“对象”的概念不只特指 JavaScript 对象,还包括函数做用域(或者全局词法做用域).函数

变量

在 js 中有全局变量个局部变量(这里的全局变量是 global object,而 client 中 js 的全局对象指的是 window,也就是当前浏览器窗口).post

全局变量在一个浏览器页面中始终是一只存在的.局部变量是在建立它的函数做用域中存在,当离开当前做用域的时候,会自动解除引用并进行释放.spa

引用计数垃圾收集

这是最初级的垃圾收集算法.此算法把“对象是否再也不须要”简化定义为“对象有没有其余对象引用到它”.若是没有引用指向该对象(零引用),对象将被垃圾回收机制回收.

var o = {
  a: {
    b:2
  }
};
// 两个对象被建立,一个做为另外一个的属性被引用,另外一个被分配给变量o
// 很显然,没有一个能够被垃圾收集


var o2 = o; // o2变量是第二个对“这个对象”的引用

o = 1;      // 如今,“这个对象”的原始引用o被o2替换了

var oa = o2.a; // 引用“这个对象”的a属性
// 如今,“这个对象”有两个引用了,一个是o2,一个是oa

o2 = "yo"; // 最初的对象如今已是零引用了
           // 他能够被垃圾回收了
           // 然而它的属性a的对象还在被oa引用,因此还不能回收

oa = null; // a属性的那个对象如今也是零引用了
           // 它能够被垃圾回收了

限制:循环引用

该算法有个限制:没法处理循环引用的事例.在下面的例子中,两个对象被建立,并互相引用,造成了一个循环.它们被调用以后会离开函数做用域,因此它们已经没有用了,能够被回收了.然而,引用计数算法考虑到它们互相都有至少一次引用,因此它们不会被回收.

function f(){
  var o = {};
  var o2 = {};
  o.a = o2; // o 引用 o2
  o2.a = o; // o2 引用 o

  return "azerty";
}

f();

标记清除算法

这个算法把“对象是否再也不须要”简化定义为“对象是否能够得到”.

标记清除算法分为标记和清除两个阶段.这个算法假定设置一个叫作根(root)的对象(在 Javascript 里,根是全局对象).垃圾回收器将按期从根开始,找全部从根开始引用的对象,而后找这些对象引用的对象,而后对这些对象进行标记……从根开始,垃圾回收器将找到全部能够得到的对象和收集全部不能得到的对象.以后进入了清除阶段,标记的对象会与内存中的对象进行比较,而后清除内存中那些没有标记的对象

  • 标记阶段,它将遍历堆中全部对象,并对存活的对象进行标记;
  • 清除阶段,对未标记对象的空间进行回收.

这是 JavaScript 中最多见的垃圾回收方式.从 2012 年起,全部现代浏览器都使用了标记-清除的垃圾回收方法,低版本 IE 采用的是引用计数方法.

标记整理算法

Mark-Compact (标记整理)算法正是为了解决标记清除所带来的内存碎片的问题,提升对内存的利用.标记整理在标记清除的基础进行修改,标记阶段与标记清除相同,可是对未标记的对象处理方式不一样,将其的清除阶段变为紧缩极端.与标记清除是对未标记的对象当即进行回收,标记整理则将活着的对象向内存区的一段移动,移动完成后直接清理掉边界外的内存.紧缩过程涉及对象的移动,因此效率并非太好,可是能保证不会生成内存碎片.

doc

原文出处:https://www.cnblogs.com/mybilibili/p/11819148.html

相关文章
相关标签/搜索