「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」
内存
编写代码时,我们常说要防止内存泄漏,少用闭包,达到前端性能优化
那么内存是怎么回收的,这与浏览器的v8引擎息息相关,关键点在于垃圾回收机制
垃圾回收的机制,工作内容就是查找垃圾释放空间、回收空间,它的方式有多种,也就是我们常说的GC算法
GC算法
GC算法基础为3个,v8常用的GC算法不止3个,但是也是基础的升华,下文回收策略分解
引用计数
标记清除
标记整理
引用计数 核心思想:设置引用数,判断当前引用数是否为0
引用计数器
引用关系改变时修改引用数字
引用数字为0时立即回收
优点:
- 发现垃圾时立即回收
- 最大限度减少程序暂停
缺点: - 无法回收循环引用的对象
- 时间开销大
// 缺点1
function fn(){
const obj1 = {}
const obj2 = {}
obj1.name = obj2
obj2.name = obj1
return '循环引用'
}
标记清除 核心思想:分标记和清除两个阶段完成
遍历所有对象找到标记活动对象
遍历所有对象清除没有被标记对象
回收相应的空间
优点:1. 解决循环引用不能回收的问题
缺点:1. 会产生空间碎片化的问题,浪费空间
标记整理 标记整理 可以看作是 标记清除 的增强
标记阶段的操作和标记清除一致
清除阶段会执行整理,移动对象位置
优点:1. 减少碎片化空间
缺点:1. 不会立即回收垃圾对象
V8
- v8是一款主流的JavaScript执行引擎
- v8采用即时编译
- v8内存设限 64位不超过1.5g,32位不超过800m(操作系统)
V8垃圾回收策略
核心:采用分代回收思想
整个回收过程v8常用的GC算法:
分代回收
空间复制
标记清除
标记整理
标记增量
v8将内存一分为二,分为新生代、老生代
新生代对象回收实现 新生代指的是存活时间较短的对象
用于存储新生代对象的空间较小( 32M|16M )
- 回收过程采用复制算法+标记整理
- 新生代内存区分为2个等大的空间
- 使用空间为From,空闲空间为To
- 活动对象存储于From空间
- 标记整理后将活动对象拷贝至To
- From与To交换空间完成释放 回收细节说明:
- 拷贝过程中可能出现晋升
- 晋升就是将新生代对象移动至老生代
晋升的2个触发条件: - 一轮GC还存活的新生代需要晋升
- To空间的使用率超过25%
老生代对象回收实现 老生代对象就是指存活时间较长的对象
用于存储新生代对象的空间较大,64位操作系统1.4G,32操作系统700M
主要采用标记清除、标记整理、增量标记算法
- 首先使用标记清除完成垃圾空间的回收
- 采用标记整理进行空间优化(当新生代晋升时并且老生代空间不足时)
- 采用增量标记进行效率优化
细节对比:
- 新生代区域垃圾回收使用空间换时间(有一半是空闲的)
- 老生代区域垃圾回收不适合复制算法
标记增量如何优化垃圾回收:
将整段垃圾回收操作拆分成多个小步,组合完成垃圾回收,这样可以让垃圾回收与主程序交替执行,这样时间消耗更合理,用户体验更好
总结
GC的目的是为了实现内存空间的良性循环,但作为良好程序员的我们应该节约使用内存,避免频繁的垃圾回收,因为GC工作时应用程序是停止的,频繁且过长的GC会导致应用假死,用户使用中感知应用卡顿!