JS内存回收机制——GC

1,311 阅读6分钟

概念

GC,全称Garbage Collection,即垃圾回收的简写。

GC是什么?

GC是一种机制,垃圾回收器完成具体的工作,而工作内容就是查找垃圾释放空间,回收空间。GC中的算法就是工作时查找和回收所遵循的规则

内存管理

在JS中,内存管理是自动的,由JS引擎负责创建对象、销毁对象,以及垃圾回收即可以理解为内存空间的申请,使用和释放。

内存问题

问题表现

  1. 页面出现延迟加载或经常性暂停
  2. 页面出现持续性得到糟糕的性能(内存膨胀)
  3. 页面性能随时间延长越来越差

内存泄漏:内存使用持续升高
内存膨胀:在多数设备上都存在性能问题
频繁垃圾回收:

  1. 通过内存变化图可进行分析
  2. 用户在使用中会感知明显的卡顿
  3. 频繁且过长的GC会导致应用假死
  4. Timeline中频繁的上升下降
  5. 任务管理器数据频繁的增加减小

内存监控的几种方式

  1. 浏览器的任务管理器(F12 + shift + ESC)
  2. Timeline时序图记录(F12 -> Performance)
  3. 堆快照查找分离DOM(F12->Memory):如下 DOM存在的几种状态?
  • 界面元素存活在DOM树上
  • 垃圾对象时的DOM节点 —— DOMDOM树上脱离了,js里面也没有引用。
  • 分离状态的DOM节点 —— DOMDOM树上脱离了,js里面有引用,界面上看不见,存在内存里面(可当做垃圾)。

对象的可达性

可理解为从根节点可以到达(引用)的对象。JS的根可以理解为当前的全局对象,如window

  1. 所有显示调用,被称为,包括
    • 全局对象
    • 正被调用的函数的局部变量和参数
    • 相关嵌套函数里的变量和参数
    • 其他(引擎内部调用的一些变量)
  2. 所有从根引用或引用链访问的对象

常见的GC算法

引用计数算法

核心思想:程序会对一个变量的引用次数进行记录,当声明一个变量,并将引用类型赋值给该变量,然后引用类的引用数量+1,在系统运行时,垃圾回收机制就会判断这个引用类的引用数量,如果引用数量为0,就会立即回收该内存。
优点:

  1. 发现垃圾时立即回收
  2. 能够最大限度的减少程序暂停 缺点:
  3. 无法回收循环引用的对象 如下:
   var a ={
       name:'a',
       friend:b
   }
   var b = {
       name:'b',
       friend:a
   }

标记清除算法

核心思想:将垃圾回收分为标记和清除两个阶段,首先遍历所有对象找到活动对象进行标记,然后遍历所有对象清除没有标记的对象
优点:

  1. 相对以上,能够解决循环调用问题 缺点:
  2. 空间碎片化
  3. 不会立即回收

标记整理

核心思想:标记整理可以看作是标记清除的增强版,标记阶段和上面一致,只是在清理阶段会先执行整理,移动对象位置再清除未标记的对象 优点:

  1. 相对以上,能够解决空间碎片化的问题

V8 引擎(主要学习垃圾回收策略)

特点:即时编译、内存涉限(64位位1.5G;32位800M)

垃圾回收策略

采用分代回收的思想,将内存分为新生代、老生代区,针对不同区采用不同的垃圾回收算法。常用的GC算法有:分代回收、空间复制、标记清除、标记整理、标记增量。

分代回收

首先将内存一分为二,小空间(64位32M;32位16M)用于存储新生代对象(存活时间较短的对象),大空间用于存储老生代对象,如下:

image.png

新生代对象回收:

回收过程采用复制算法 + 标记整理算法,先将新生代内存区分为两个等大小空间,使用空间为From,空间空间为To。

  1. 首先会将所有活动对象存储于From空间,这个过程中To是空闲状态。
  2. From空间使用到一定程度之后就会触发GC操作,这个时候会进行标记整理对活动对象进行标记并移动位置将使用空间变得连续,便于后续不会产生碎片化空间。
  3. 活动对象拷贝至To空间,拷贝完成之后活动空间就有了备份,这个时候就可以考虑回收操作了。
  4. From空间完成释放,回收完成
  5. FromTo名称进行调换,继续重复之前的操作。 在拷贝过程中会出现晋升(将新生代对象移动至老生代中),发生晋升的条件有:
  6. 一轮GC后还存活的新生代对象
  7. To空间的使用率超过25%:?:来回的拷贝操作要复制From到To,对空间有一定要求,如果To使用过高,就会出现新对象复制不进来。

老生代回收

回收过主要采用标记清除、标记整理、增量标记算法

  1. 首先使用标记清除完成垃圾空间的回收
  2. 采用标记整理进行空间优化:?:在晋升的时候且老生代区域的空间也不够容纳的时候,就会采用标记整理进行 空间优化
  3. 采用增量标记进行效率优化:?:将一整段的垃圾回收操作标记拆分成多个小段完成回收,主要是为了实现程序和垃圾回收的交替完成,这样进行 效率优化 带来的时间消耗更加的合理

增量标记介绍:
系统执行可以看做存在两个部分,一个是程序执行,一个是垃圾回收。当垃圾回收的时候回阻塞程序的执行,而阻塞时就会出现空档期,阻塞太久会让用户体验不好。所以增量标记采用交替执行的方法,降低每次阻塞的时间如下图:

image.png

总结

新生代区域垃圾回收 以空间换取时间,主要采用复制算法和标记整理算法
老生代由于空间大适合采用复制算法
增量标记算法能够提高回收效率,优化体验

V8执行流程(略微了解)

image.png