1. 什么是内存管理
编程中的内存管理涉及控制程序运行时内存的分配和释放。像许多高级语言一样,JavaScript通过一个垃圾回收(Garbage collection)的过程使用自动内存管理。这使开发者不必显式管理内存,但了解内存何时分配和释放是非常必要的,可以防止内存泄漏和过度消耗内存等问题。
内存生命周期
- 内存分配 - 为变量、对象和函数预留内存的过程。
- 内存使用 - 使用已分配的内存(例如,读取或写入变量,调用函数)。
- 内存释放 - 一旦不再需要内存,就应该将其释放(在JavaScript中,这是通过垃圾回收(Garbage collection)完成的)。
2. JavaScript中的内存分配
当变量被声明或创建对象和函数时,JavaScript会自动分配内存。
当我们声明一个原始值时,JavaScript会为该值分配内存,并直接将值存储在变量中。原始类型数据直接存储在栈中,并且具有固定大小。
对于非Primitive Values 当我们创建一个对象、数组或函数时,它们都存储在堆中,变量包含一个引用(或指针)指向堆中的内存位置。这些类型没有固定大小,并且可以动态增长。
3. 垃圾回收
JavaScript通过一个垃圾回收的过程自动释放不再使用的内存。JavaScript引擎用于垃圾回收的最常见算法是:标记和清除算法。
标记和清除算法
它的工作原理如下:
-
标记阶段 - 垃圾回收器标记所有可到达的变量和对象(即可从root访问,如全局变量、当前函数调用栈和事件侦听器)。这些变量被认为是alive的。
-
清除阶段 - 然后它检查不可到达的变量和对象(即不存在对它们的引用)。这些对象被认为是垃圾,并被移除,然后内存空间得以释放。
4. 内存泄漏
当不再使用的内存没有被释放时,就会发生内存泄漏。这可能导致你的应用程序随着时间的推移消耗越来越多的内存,导致性能下降甚至崩溃。内存泄漏通常是由于不可到达的对象仍然在代码的某个部分被引用,垃圾回收器无法移除它们而引起的。
常见的可能发生内存泄露的问题包括:
1.setTimeout
和setInterval
这样的定时器没有被清除。
2.非预期的全局变量 未使用var
、let
和const
声明变量会被当成隐式声明的全局变量,这些变量在整个页面的生命周期内存在,并且不会被垃圾回收。
3.错误的使用闭包