【JS核心概念】内存管理机制

一、内存模型

JS内存空间分为栈、堆、池,其中栈存放变量,堆存放复杂对象,池存放常量。

1. 基本数据类型与栈内存

JS中的基本数据类型都有固定的大小,往往都保存在栈内存中,由系统自动分配存储空间,我们可以直接操作保存在栈内存中的值,因此基本数据类型都是按值访问。

说到栈呢,大家都会想到数据结构中的栈先进后出、后进先出的特点,于是很多人会容易产生误解,认为JS中的基本数据类型的赋值和使用遵循栈的先进后出原则:

    var a = 1;
    var b = 2;
    var c = 3;

如上代码段,a、b、c三个变量都是存储在栈内存中的,如果遵循先进后出,那当要访问变量a的时候,是不是要先将变量b、c弹出呢?

显然不会是这样的哈,所谓先进后出,不是说赋值为进,使用为出,而应该是赋值为进,释放为出。在同一作用域下的变量,应该位于栈的同一层。所谓的变量存储于栈内存中的栈,传统意义上说指的是由内存自动创建分配的空间,例如函数的参数值与局部变量,只是其操作方式类似于栈操作,所以叫栈内存。

    function foo() {
        var a = 1;
        bar();
    }
    
    function bar() {
        var b = 2;
        baz();
    }
    
    function baz() {
        var c = 3;
    }
    foo();

如上,这里的声明顺序显然是 1 2 3,释放顺序显然是 3 2 1。

2. 引用数据类型与堆内存

JS中的引用数据类型,比如Array,它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。JS不允许直接访问堆内存中的数据,因此我们不能直接操作对象的堆内存空间。在操作对象的时候,实际上操作的是对象的引用而不是实际的对象。因此引用数据类型的值都是按引用访问的,这里的引用,我们可以理解为是保存在栈内存中的一个地址,该地址表示的是对象在堆内存中的位置。当我们要访问引用类型的值的时候,会先在栈内存中找到地址,然后根据地址去堆内存中查找对象。

其他内容可以看看《01、变量》

二、内存的生命周期

JS环境中分配的内存一般有如下生命周期:

  • 内存分配:当我们声明变量、函数时,系统会自动为他们分配内存;
  • 内存使用:使用值得过程是对分配的内存进行读取与写入的操作;
  • 内存回收:使用完毕,由垃圾回收机制自动回收不再使用的内存。

三、垃圾回收机制

  • 垃圾回收算法主要依赖于引用的概念。在内存管理的环境中,一个对象如果有访问另一个对象的权限(隐式或者显示),焦作一个对象引用另一个对象。
  • 引用计数垃圾收集:这是最初级的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。该算法有个限制:无法处理循环引用。
  • 标记-清除算法:这个算法把“对象是否不再需要”简化定义为“对象是否可获得”。这个算法假定设置一个叫做根(root)的对象(在JavaScript里,根是全局对象)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象。那些无法从根对象查询到的对象都将被清除。





原文地址:https://www.cnblogs.com/jiafifteen/p/12201469.html