JavaScript内存管理主要涉及到堆(Heap)和栈(Stack),以及任务队列(Task Queue)和调
用栈(Call Stack)。
1.堆(Heap)
- 存储对象与分配的动态内存。
- 当你创建一个新的对象
{}
,数组[]
,或者任何其他复杂类型时,它们会被分配在堆上。
2.栈(Stack)
- 存储基本类型数据(如Numbers, Strings, Booleans, Null, Undefined)和指向堆上对象的指针
- 当你创建一个变量并将一个原始值赋值给它时,如
let a = 5;
,这个值会被存储在栈上。 - 调用函数时,函数的环境(包括局部变量)会被推入调用栈。
3.任务队列(Task Queue)
- 存储异步操作的回调,如setTimeout, setInterval, Promise, Fetch等。
-
当这些异步操作完成时,其回调函数会被推入任务队列等待执行。
4.调用栈(Call Stack)
-
当JavaScript运行时,它会按顺序执行调用栈的函数。
-
当执行完所有同步代码或遇到异步操作时,会将控制权交给浏览器的事件循环。
在JavaScript中,调用栈(call stack)是一个存储函数调用的地方,其中JavaScript引擎使用这个栈来管理代码执行的顺序。当调用函数时,它会被添加到调用栈的顶部。当函数执行完毕并返回时,它会从调用栈的顶部移除。
当调用栈达到最大大小时,会引发"栈溢出"错误。这通常发生在无限递归或处理大量的同步调用时。
在浏览器环境中,当调用栈为空时,事件循环开始运行。事件循环是JavaScript运行时的一部分,它处理各种事件(例如用户的点击,API调用的返回,setTimeout的时间到达等),当这些事件处理完毕后,它将控制权交还给调用栈,继续执行代码。
JavaScript 的内存管理主要是通过垃圾回收机制来自动处理的,其中最著名的垃圾回收算法是引用计数和标记清除。
-
引用计数: 当一个对象被创建时,系统会记录有多少变量指向这个对象,如果这个数量降到0,那么这个对象就会被垃圾回收器回收。但是这种方法有一个问题,就是循环引用,如果两个对象相互引用,那么这两个对象的引用计数永远不会降为0,因此这种方法在现代浏览器中已经不再使用。
-
标记清除: 这是现代浏览器使用的垃圾回收算法。工作原理是,当代码执行过程中,运行环境会追踪哪些变量正在被使用,然后在执行垃圾回收时,清除未被追踪的变量。
在JavaScript中,可以使用new
关键字创建对象,使用delete
操作符删除对象的属性,或者将对象的引用设置为null
来手动释放内存