# 为什么使用Performance
- GC的目的是为了实现内存空间的良性循环
- 良性循环的基石是合理使用
- 必须时刻关注内存变化才能确定是否合理
- Performance提供多种监控内存的方式,可以通过Performance实时监控内存变化
# Performance使用步骤
- 打开浏览器输入目标网址
- 进入开发人员工具面板,选择性能
- 开启录制功能,访问具体界面
- 执行用户行为,一段时间后停止录制
- 分析界面中记录的内存信息
# 内存问题的体现
# 内存问题的外在表现
(假设网络环境正常)
- 页面出现延迟加载或经常性暂停(可能由于有频繁的垃圾回收,说明代码让内存短时间沾满)
- 页面持续性出现糟糕的性能(可能底层存在内存膨胀,当前界面为了达到一定的运行速度,而申请了更多的内存空间,从而超过了本机的承载)
- 页面的性能随时间延长越来越差(可能存在内存泄漏,也就是代码执行过程中,回收的空间越来越少,越来越多的空间无法回收)
# 常见的内存监控方式
# 界定内存问题的标准
- 内存泄漏:内存使用持续升高
- 内存膨胀:在多数设备上都存在性能问题(可能在多种设备上体现,可能是由于硬件不支持,但如果对多个通用设备上测出相同的问题,就可能是程序本身的问题)
- 频繁垃圾回收:通过内存变化图进行分析
# 监控内存方式
- 浏览器任务管理器
- Timeline时序图记录
- 对快照查找分离DOM(分离DOM也就是一中内存泄漏)
- 判断是否存在频繁的垃圾回收
# 任务管理器监控内存
- 在浏览器中通过右上角更多操作的更多工具找到任务管理器(或者使用快捷键Shift+Esc)
- 选中其中一栏右键选择JS内存,主要关注内存和JS内存
- 内存表示原生内存,也就是DOM节点展示所需的内存,如果不断增大说明不停在操作DOM
- JS内存表示JS堆,括号内表示可达引用使用的内存,如果没有变化说明没有增长,如果不停增长,说明GC没有运行,JS代码可能有问题
- 缺点是任务管理器监控内存只能告诉我们有没有问题,而不能定位问题
# Timeline记录内存
- 在浏览器的任务管理器中无法定位具体问题,可以通过浏览器性能(performance)功能的时间线记录内存,可以让我们精确定位内存异常问题发生的时间和代码
- 通过模拟一连串dom操作,会发现在dom操作期间内存瞬间飙升,然后趋于平稳,接着出现下降,然后再次点击时发现如此往复。
- 内存占用的下降就说明v8的垃圾回收启动,在js代码趋于稳定期间运行垃圾回收清理内存。
- 如果出现内存一直增长,没有内存的下降,就说明可能有内存问题,很有可能是内存泄漏
- 我们还可以通过时间线监控在那个时段发生了内存问题,且可以看到此时的DOM变化。
图1 内存变化图
# 堆快照查找分离DOM
# 什么事分离DOM
- 界面元素存活在DOM树上
- 垃圾对象时的DOM节点(脱离了DOM树,且没有js代码引用的DOM节点)
- 分离状态的DOM节点(脱了DOM树,在js代码中还有引用,虽然看不见,但在js内存中还占用空间)
演示分离DOM
<body>
<button id="btn">add</button>
<script>
let tmpEle;
function fn() {
let ul = document.createElement("ul");
for (let i = 0; i < 10; i++) {
let li = document.createElement("li");
ul.appendChild(li);
}
tmpEle = ul; // 此处只是将ul挂到了tmpEle上面, 但是又没有挂载到页面上, 这里的11个节点就是分离DOM
}
document.getElementById("btn").addEventListener("click", fn);
</script>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
运行这个html然后在点击事件前后获取堆快照发现如图2和图3所示
图2 点击前的堆快照图示
图3 点击后的堆快照图示
- 当未点击add之前,堆快照中未发现分离的DOM,而点击后则发现多出的11新的DOM节点,又没有挂在DOM树上都是分离的DOM
- 要清除这些分离的DOM只需要,
tmpEle = null
,将temEle置为null即可,这样新产生的DOM节点就没有被引用,也就会被当做垃圾回收 - 堆快照可用于专门查找分离DOM,这种页面中未渲染,却被对象引用,占用内存,这样就会造成内存浪费,我们就可以通过堆快照去查找这些分离的DOM节点然后在代码中将其清除,GC就会将其回收,避免内存浪费。
# 判断是否存在频繁GC
# 为什么确定频繁垃圾回收
- GC工作时应用程序是停止的
- 频繁且过长的GC会导致应用假死
- 用户使用中感知应用卡顿
# 确定频繁的垃圾回收
- Timeline中频繁的上升下降
- 任务管理器中数据频繁的增加减小
# Performance总结
- Performance使用流程
- 内存问题的相关分析(内存泄漏、内存膨胀、频繁GC)
- Performance时序图监控内存变化
- 任务管理器监控内存变化
- 堆快照查找分离DOM