JavaScript 性能优化
简单概要
- 内存管理
 - 垃圾回收与常见 GC 算法
 - V8 引擎的垃圾回收
 - Performance 工具
 - 代码优化栗子
 
内存管理
简单叙述内存,下面是一个小 codefunction fn() {
    arr = []
    arr[1000000] = 'hellow'
}
fn()
// 如果不是很了解内存机制,就有可能编写出这样的代码,内存是持续升高,并没有回落,蓝色线条

内存管理介绍
- 内存:由可读写单元组成,表示一片可操作空间
 - 管理:人为的去操作一片空间的申请、使用和释放
 - 内存管理:开发者主动申请空间、使用空间、释放空间
 - 管理流程:较为简单,申请-使用-释放、
 
// 申请
let obj = {}
// 使用
obj.name = 'zhang'
// 释放
obj = {}
垃圾回收
- JavaScript 中内存管理是自动的
 - 对象不再被引用时是垃圾
 - 对象不能从根上访问到时是垃圾
 
GC 垃圾是什么
- GC就是垃圾回收机制的简写
 - GC可以找到内存中的垃圾、并释放和回收空间
 - 程序中不再需要使用的对象以及程序中不能再访问到的对象就是 GC 的垃圾
 
GC 算法是什么
- GC是一种机制,垃圾回收器完成具体的工作
 - 工作的内容就是查找垃圾释放空间、回收空间
 - 算法就是工作时查找和回收所遵循的规则
 
常见 GC 算法
- 引用计数
 - 标记清除
 - 标记整理
 - 分代回收
 
const user1 = {age: 11}
const user2 = {age: 22}
const user3 = {age: 33}
const nameList = [user1.age, user2.age, user3.age]
function fn(){
    const num1 = 1
    const num2 = 2
}
fn()
当上述代码 fn() 执行完毕后,由于 num1 和 num2 加上了 const 声明,所以外部访问不到,这时 num1 和 num2 身上的引用计数会变成 0,当引用计数为 0时,GC就会把他当成垃圾回收掉,而 user123,因为被数组 nameList 引用着,所以不会被回收。
引用计数算法优点:【发现垃圾时立即回收】【最大限度减少程序暂停】
缺点:【无法回收循环引用的对象】【时间开销大】
二、标记清除算法。
核心思想:分标记和清除两个阶段完成
阶段一:遍历所有对象找标记活动对象
阶段二:遍历所有对象清除没有标记对象
回收相应的空间
标记清除算法优点:【可以解决循环引用不能回收问题】 缺点:【会产生空间碎片化问题,不能让空间得到最大化使用】
V8 引擎
- V8 是一款主流的 JavaScript 执行引擎
 - V8 采用即时编译
 - V8 内存设限
 
垃圾回收策略
- 采用分代回收
 - 内存分为新生代、老生代
 - 针对不同对象采用不同算法
 

- 分代回收
 - 空间复制
 - 标记清除
 - 标记整理
 - 标记增量
 
V8 内存分配
- V8 内存空间一分为二
 - 小空间用于存储新生代对象(32M|16M)
 - 新生代指的是存活时间较短的对象
 
V8 回收新生代对象
- 回收过程采用复制算法 + 标记整理
 - 新生代内存区分为二个等大小空间
 - 使用空间为 From,空闲时间为 To
 - 活动对象存储于 From 空间
 - 标记整理后将对象拷贝至 To
 - From 与 To 交换空间完成释放
 
V8 老生代对象存放区域
- 老生代对象存放在右侧老生代区域
 - 64 位操作系统 1.4 G,32 操作系统 700M
 - 老生代对象就是指存活时间较长的对象
 
老生代对象回收实现
- 主要采用标记清除、标记整理、增量标记算法
 - 首先使用标记清除完成垃圾空间的回收
 - 采用标记整理进行空间优化
 - 采用增量标记进行效率优化
 
Performance 监控面板
- 可以使用 chrome 的开发人员工具面板,选择性能
 - 开启录制功能,访问具体界面
 - 执行用户行为,一段时间后停止录制
 - 分析界面中记录的内存信息
 
- 页面出延迟加载或经常性暂停(可能伴随着频繁垃圾回收出现,在于有些代码瞬间让程序爆炸)
 - 页面持续性出现糟糕的性能(内存膨胀,指的是当前界面为了达到最近使用速度,会申请内存空间,但是这个内存空间大小超过了设备本身所提供的大小)
 - 页面的性能随时间延迟越来越差(内存泄露)
 
- 浏览器任务管理器
 - Timeline 时序图记录
 - 堆快照查找分离 DOM
 - 判断是否存在频繁的垃圾回收