js垃圾回收机制

一、基本概念

1.内存管理

  • 内存: 由可读写单元组成, 表示一片可操作空间
  • 管理: 人为的去操作一片空间的申请, 使用和释放
  • 内存管理: 开发者主动申请空间, 使用空间, 释放空间
  • 管理流程: 申请-使用-释放

2.垃圾回收

  • JavaScript中内存管理是自动的
  • 对象不再被引用时是垃圾
  • 对象不能从根上访问到时是垃圾
3.可达对象
  • 可以访问到的对象就是可达对象 (引用, 作用域链)
  • 可达的标准就是从根出发是否能够被找到
  • JavaScript 中的根就可以理解为是全局变量对象

4.GC定义与作用

  • GC就是垃圾回收机制的简写
  • GC可以找到内存中的垃圾, 并释放和回收空间
  • GC里的垃圾是什么:
    • 程序中不再需要使用的对象
    • 程序中不能再访问到的对象
  • GC算法是什么
    • GC是一种机制, 垃圾回收器完成具体的工作
    • 工作的内容就是查找垃圾释放空间, 回收空间
    • 算法就是工作时查找和回收所遵循的规则
    • 常见 GC 算法
      • 引用计数
      • 标记清除
      • 标记整理
      • 分代回收

5.引用计数算法

  • 核心思想: 设置引用数, 判断当前引用数是否为0
  • 计数器
  • 引用关系改变时修改引用数字
  • 引用数字为0时立即回收
  • 优点
    • 发现垃圾时立即回收
    • 最大限度减少程序暂停 (防止内存暂满)
  • 缺点
    • 无法回收循环引用的对象
    • 时间/资源开销大 (需要维护数值的变化,时刻监控当前对象的数值是否需要修改, 本来对象引用数值的修改就需要时间, 如果有更多的对象需要修改, 时间开销就更大)

6.标记清除算法实现原理

  • 核心思想: 分标记和清除两个阶段完成
  • 遍历所有对象找标记活动对象
  • 遍历所有对象清除没有标记对象
  • 回收相应的空间
  • 优点:
    • 可以解决对象循环引用的问题 (函数调用之后, 内部成员在全局不可访问,所以未做标记)
  • 缺点
    • 空间碎片化: 回收的垃圾对象在地址上是不连续的, 回收之后分散在各个角落, 后续想要使用的时候, 新的空间匹配就能用, 多了或者少了就不太适合使用了
    • 不会立即回收垃圾对象
    • 清除时程序是停止工作的

 

7.标记整理算法实现原理

  • 标记整理可以看做是标记清除的增强
  • 标记阶段的操作和标记清除一致
  • 清除阶段会先执行整理, 移动对象位置, 让他们在地址上产生连续
  • 优点
    • 减少碎片化空间
  • 缺点
    • 不会立即回收垃圾对象

 

8.V8

  • V8是一款主流的JavaScript执行引擎
  • V8采用即时编译
  • V8内存设限(32位不超过800m, 64位不超过1.5g)

V8垃圾回收策略

  • 采用分代回收的思想
  • 内存分为新生代, 老生代
  • 针对不同对象采用不同算法
  • V8中常用的GC算法
    • 分代回收
    • 空间复制
    • 标记清除
    • 标记整理
    • 标记增量
  • V8如何回收新生代对象
    • V8内存空间一分为二
    • 小空间用于存储新生代对象 (32M|16M)
    • 新生代指的是存活时间较短的对象
    • 新生代对象实现回收
      • 回收过程采用复制算法 + 标记整理
      • 新生代内存区分为两个等大小的空间
      • 使用空间为 From, 空闲空间为 To
      • 活动对象存储于 From 空间
      • 标记整理后将活动对象拷贝至 To
      • From释放之后 与 To 交换空间完成释放
    • 回收细节说明
      • 拷贝过程中可能出现晋升
      • 晋升就是将新生代对象移动至老生代进行存储
      • 一轮GC之后还存活的新生代需要晋升
      • 拷贝过程中发现 To 空间的使用率超过 25%
  • V8如何回收老生代对象
    • 老年对象存放在右侧老生代区域
    • 64位操作系统1.4G, 32位操作系统700M
    • 老年带对象就是指存活时间较长的对象(全局, 闭包...)
    • 老年代对象回收实现
      • 主要采用标记清除, 标记整理, 增量标记算法 (mark-compact
      • 首先使用标记清除完成垃圾空间的回收
      • 采用标记整理进行空间优化
        • 当新生代区域往老生代晋升, 老生代空间不足以存放需要移过来的对象
      • 采用增量标记进行效率提升
  • 细节对比
    • 新生代区域垃圾回收使用空间换时间(复制算法)
      • 每时每刻都会有一个空闲空间, 但是由于本来空间就很小, 这一部分空闲空间的浪费相对于时间上的提升来说是微不足道的
    • 老生代区域垃圾回收不适合复制算法
  • 标记增量如何优化垃圾回收
    • 将一整段垃圾回收操作拆分成多个小步组合着去完成当前整个回收, 从而去替代之前一口气做完的垃圾回收操作, 实现垃圾回收与程序执行交替完成, 时间消耗更加合理
    • 比如说, 程序执行一轮之后, 执行GC遍历对象, 对直接可达对象进行标记. 然后继续执行代码, 然后继续对间接可达对象进项标记, 如此循环, 直到触发GC回收机制之后完成清除, 如此反复循环 (整个V8最大的垃圾回收达到1.5G采用非增量标记形式进行垃圾回收时间也不超过1s)

 

posted @   恣肆zisi  阅读(56)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2021-04-22 前端框架面学习笔记(三)
点击右上角即可分享
微信分享提示