JavaScript内存管理机制

JavaScript内存管理机制(Memory Management)

本文核心内容来源于MDN Memory Management

内存生命周期

内存生命周期在大多数编程语言中都是一样的,见下图

在这里插入图片描述

  1. 分配内存
  2. 读写内存的值
  3. 当内存不再被使用的时候,释放内存

第二步在所有编程语言中都已经明确好的。第一步和最后一步在低级语言中通过手动方式管理,在高级语言中通过自动方式管理。

  • 手动内存管理。低级语言比如说c, c++需要程序员明确地操作内存分配和内存释放的指令,比如通过malloc()和free()
  • 自动内存管理。高级语言比如说JavaScript,可以自动地分配和释放内存。

JavaScript的内存管理

1. 内存分配

  • 值初始化分配内存
var n = 123; // allocates memory for a number
var s = 'azerty'; // allocates memory for a stringvar o = {
  a: 1,
  b: null
}; // allocates memory for an object and contained values

// (like object) allocates memory for the array and
// contained values
var a = [1, null, 'abra'];

function f(a) {
  return a + 2;
} // allocates a function (which is a callable object)

// function expressions also allocate an object
someElement.addEventListener('click', function() {
  someElement.style.backgroundColor = 'blue';
}, false);
  • 通过函数调用返回的对象分配内存
var d = new Date(); // allocates a Date object

var e = document.createElement('div'); // allocates a DOM element

2. 使用内存中的值

读写内存中变量的值或者对象的属性

let a = 1 //allocate memory
let b = 3 //allocate memory
console.log(a + b) //using values in memory

let obj = {
  name: 'Joe',
} //allocate memory

obj.name = 'Emily' //using values in memory

3. 内存释放

内存释放最难的部分在于判断分配的内存不再被使用。这也是大多数内存管理问题出现的地方。JavaScript通过垃圾回收机制(garbage collection)自动释放不再被需要的内存。判断内存是否不再被需要具有不可决定性(undecidable)。换句话说,没有哪个算法能够在所有情况下准确预判内存是否不再被需要。

垃圾回收

垃圾回收常用的算法实现引用统计(reference counting)和标记和清除算法(Mark-and-sweep)

1. 引用统计(reference counting)

这是最简单的垃圾回收算法。其原理是统计其他对象引用某对象的次数,如果引用次数为0即没有任何对象引用该对象,可以认定该对象不再被需要,可以被回收掉。

var x = { //外部对象被x引用
  a: { //内部对象作为外部对象的属性被引用
    b: 2
  }
};

var y = x;      // y引用外部对象,引用数+1

x = 1;          // x重新赋值,外部对象的引用数-1

var z = y.a;    // z引用了外部对象的属性即内部对象。内部对象引用数+1

y = 'mozilla';  // y重新赋值,外部对象引用数-1,为0,此时外部对象可以被垃圾回收,但其属性a被z引用,不能被释放
z = null;       // z重新赋值,内部对象引用数-1,为0。 外部对象被垃圾回收

局限性: 循环引用

循环引用是对象之间互相引用,形成循环,造成内存在使用完后无法被释放。见下面的例子,根据引用统计算法,x, y的引用次数为1,即使两个对象不再被需要也无法被释放。循环引用常常造成内存泄漏

function f() {
  var x = {};
  var y = {};
  x.a = y;        // x 引用了 y
  y.a = x;        // y 引用了 x

  return 'azerty';
}

f();

2. 标记和清除算法(Mark-and-sweep)

其原理是假设一些对象作为根对象(root object),从根对象出发,找出所有引用根对象的对象1,然后找出所有引用对象1的对象,以此类推。这个过程类似于bfs(宽度优先搜索)。通过这个方法,所有被遍历到的对象被认为是可以触及的(reachable),而其他没有被遍历到的对象则是不可触及的(unreachable),后者将被回收。JavaScript中,根对象是全局对象(global object),比如说’windows’。这个算法是目前常用的垃圾回收算法。在上面的例子中,在函数调用返回后,x,y不再和全局对象有任何直接或者间接的接触,因此被回收。

这个算法分为两个阶段

  1. mark阶段。对象创建后默认被标记成0(false),从根对象出发遍历过程中,被遍历到的对象被标记成1(true)。
  2. sweep阶段。遍历完成后,标记成0的对象将被回收掉。

V8引擎出现 out of memory的问题

V8引擎用于chrome浏览器和node,提供一个运行环境执行JavaScript代码。
通过-expose-gc --inspect检查memory出现的问题

通过-max-old-space-size=<6000>增加heap memory的大小

node --max-old-space-size=6000 index.js

node --expose-gc --inspect index.js
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值