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
- 判断是否存在频繁的垃圾回收