JavaScript 垃圾回收机制

334 阅读4分钟

一、内存管理

JavaScript 中内存管理是自动的

JavaScript 中的内存管理分为三个步骤

  1. 申请内存空间 let obj = {}
  2. 使用内存空间 obj.age = 18
  3. 释放内存空间 obj = null

二、什么是 JavaScript 垃圾

  • 对象不再被引用时是垃圾

  • 没有办法访问到的对象到是垃圾(不能从根上出发被访问到)

  • 用人话来解释就是,当程序中不再需要使用的对象和程序中不能再访问到的对象就是垃圾

function func(){
    const name = 'lg'
    return name
}
func()
// 当函数执行完之后,程序不再需要使用name了,并且程序也访问不到name了,这就很明显是个垃圾

知道什么是垃圾之后,javaScript 执行引擎就会出来工作,把这些垃圾所占据的内存空间进行释放回收

三、JavaScript 可达对象

  • 可以访问到的对象就是可达对象(引用、作用域链)

  • 可达的标准就是从根出发是否能被找到,这里所说的根就是 javaScript 中的全局变量对象

// { name:xxx } 这个对象空间被 obj 引用了,并且可以从根上出发被访问到,所以这个对象是可达对象
let obj = { name:xxx }

let ali = obj

// obj 对 { name:xxx } 的引用已经断掉了,但是 { name:xxx } 还是一个可达对象,因为 ali 还在引用 { name:xxx }
obj = null

三、GC 算法

  • GC 是垃圾回收机制的简写

  • GC 是一种机制,工作的内容就是查找到内存中的垃圾、并释放和回收内存空间

  • GC 算法就是 GC 工作时候查找和回收时候所遵循的规则

  • 常见的 GC 算法:

    1. 引用计数
    2. 标记清除
    3. 标记整理
    4. 分代回收

3-1 引用计数算法实现原理

  • 核心思想:就是内部去通过引用计数器,来维护当前对象的引用数,从而来判断该对象的引用数是否为零,来决定它是不是个垃圾对象。当该对象引用数为零的时候,GC 就会开始工作,将其所在的内存空间回收和释放

  • 当对象内存空间的引用关系发生改变的时候,引用计数器就会修改引用数字

  • 引用计数算法的优点:

    1. 能够发现垃圾的时候立即回收,因为是根据当前对象的引用数是否为零来判断是不是垃圾,如果找到计数器为零的对象,就立刻释放
    2. 能够最大限度减少程序暂停,因为引用计数算法是时时刻刻监视着引用数值为零的对象,当发现内存爆满的时候,就会立即释放计数器为零的对象
  • 引用计数算法的缺点:

    1. 无法回收循环引用的对象
    2. 时间的开销更大,因为时时刻刻要维护引用数的变化,要监控当前对象的引用数值

3-2 标记清除算法实现原理

  • 核心思想:就是把垃圾回收分成了两个阶段,第一个是标记阶段,会遍历所有的对象,标记可达对象,第二个是清除阶段,会遍历所有的对象,清除没有标记的对象,最终会把回收的空间放到空闲链表上,方便后续申请空间使用

  • 标记清除算法的优点:可以回收循环引用的对象,解决了引用计数算法循环引用不能回收的问题

  • 标记清除算法的缺点:产生空间碎片化的问题,就是回收的内存空间本身是不连续的,由于这种不连续导致回收之后他们分散在各个角落,后续像去使用的时候不方便

3-3 标记整理算法实现原理

  • 核心思想:标记整理可以看做是标记清楚的增强,二者标记阶段的操作是一样的,都会遍历所有的对象,将所有可达活动对象做一个标记,在清除阶段,标记整理算法会先执行整理,移动对象位置,让他们能在地址上产生连续,所以回收后的空间内存不是分散的,是连续的,后续使用的时候可以最大化使用回收后的内存空间