JavaScript 内存空间

内存种类

JavaScript的内存分为三种

  • 栈:保存基本数据类型、引用类型的指针。
  • 池:池保存常量,一般归类到栈中。
  • 堆:保存引用数据类型。

栈的优势就是存取速度比堆要快,但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。

堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,垃圾收集器会自动地收走这些不再使用的数据,但是缺点是由于在运行时动态分配内存,所以存取速度较慢。

内存回收

JavaScript 中的内存管理是自动执行的,我们创建的每个变量、方法都会占用一部分内存。当内存不再被使用时,会被垃圾收集器(GC)自动回收。

内存泄露

当不需要的内存因为某种原因没有系统回收。
常见的会造成内存泄露的几个原因:

  1. 错误的全局变量
    全局作用域内的变量不会被系统自动回收,因为顶级对象一直存在。浏览器环境内顶级对象是window,node环境下是Global。

  2. 闭包
    下面这段代码中c\b\c其实并没有被用到,但是他们存在于add和subtract的作用域链中,占用的无法被系统回收。
    华勇

闭包会引用包含函数的整个活动对象。即使闭包不直接引用变量,包含函数的活动对象中也仍然会保存一个引用。(《JavaScript高级程序设计》第三版第184页)

const demo = (function () {
  let a = 0;
  let b = 0;
  let c = 0;
  let num = 0;
  return {
    add() {
      return ++num;
    },
    subtract() {
      return --num;
    }
  }
})();
  1. console
    控制台里打印的对象不会被系统回收,建议转成字符串再打印。

  2. 未停止的定时器
    通过setTimeout, setInterval来实现延迟执行,如果没有通过clearTimeout, clearInterval手动停止会一直占用内存,而且在部分浏览器里会即便出现关闭页面也会一直占用内存的情况。

  3. 移除DOM但未在JS中断开引用
    如下面这段代码,打印a时虽然元素已经在页面上被移除,但还是可以输出DOM对象。

    var a = document.querySelector('#app');
    a.parentNode.removeChild(a);
    console.log(a);
`` 

6. 循环引用
如下,a和b的引用数至少是1,所以不会被GC清理。
```javascript
    const a = {};
    const b = {};
    a.a = b;
    b.b = a;

如何减少内存泄漏的风险

  • 不再使用的变量及时解除引用a = null;
  • 开启严格模式,避免错误的添加全局变量。
  • 生产环境减少使用console
  • 及时清除定时器

你可能感兴趣的:(JavaScript 内存空间)