【JavaScript】内存管理和垃圾回收机制

内存管理

C 语言这样的底层语言一般都有底层的内存管理接口,比如 malloc()和free()。而 JavaScript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。

整个过程为:分配内存 -> 使用内存 -> 清理内存。

JavaScript 在定义变量或者函数调用时就完成了内存分配:

var n = 123; // 给数值变量分配内存

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,
);

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

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

垃圾回收机制

1. 引用计数

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

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

o = 1; // 现在,“这个对象”只有一个 o2 变量的引用了,“这个对象”的原始引用 o 已经没有

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();

2. 标记清除

过程分为:标记 -> 清除。

首先,遍历根(root)上的所有对象,给他们打上标记。然后在代码执行结束后,对从根开始使用过(引用过)的变量取消标记,清除掉具有标记的内存对象,释放内存。

你可能感兴趣的:(JavaScript,javascript,开发语言,ecmascript)