1. 描述
2. 内存管理
内存:由可读写单元组成,表示一片可操作的空间
管理:人为的去操作一片空间的申请、使用和释放
内存管理:开发者主动申请空间、使用空间、释放空间
管理流程:申请---使用---释放
javascript中的内存管理
1\. 申请内存空间 // let obj = {}
2\. 使用内存空间 // obj.name = 'wx'
3\. 释放内存空间 // obj = null
3. JavaScript中的垃圾回收
javascript 中内存管理是自动的
对象不再被引用时是垃圾
对象不能从根上访问到时是垃圾
4. GC算法介绍
GC 就是垃圾回收机制的简写
GC 可以找到内存中的垃圾,并释放和回收空间
GC 里的垃圾是什么?
1\. 程序中不再需要使用的对象
function func (){
name = 'lg'
return `${name} is a coder`
}
func()
2\. 程序中不能再访问到的对象
function func() {
const name = 'lg'
return `${name} is a coder`
}
func()
GC 算法是什么?
1\. GC 是一种机制,垃圾回收器完成具体的工作
2\. 工作的内容就是查找垃圾释放空间、回收空间
3\. 算法就是工作时查找和回收所遵循的规则
常见GC算法
1\. 引用计数: 通过一个数字来判断当前的一个对象是不是一个垃圾
2\. 标记清除: 在进行工作的时候,可以给活动对象添加一个标记拉判断是否是垃圾
3\. 标记整理: 类似上面
4\. 分代回收: v8会用到
5. 引用计数算法实现原理
核心思想:设置引用数,判断当前引用数是否为0
引用计数器
引用关系改变时修改引用数字
引用数字为0时立即回收
6. 引用计数算法优缺点
引用计数算法优点
1. 发现垃圾时立即回收
2. 最大限度减少程序暂停
引用计数算法缺点
1. 无法回收循环引用的对象
2. 时间开销大
7. 标记清除算法实现原理
核心思想:分标记和清除两个阶段完成
1\. 遍历所有对象找标记活动对象
2\. 遍历所有对象清除没有标记对象(会把第一个阶段标记给抹掉,回收相应空间)
8. 标记清除算法优缺点
标记清除算法优点:可以解决对象循环引用的回收操作
标记清除算法缺点:空间的碎片化,不能使空间得到最大的使用
9. 标记整理算法实现原理
标记整理可以看做是标记清除的增强
标记阶段的操作和标记清除一致
清除阶段会先执行整理,移动对象位置
优点:减少碎片化空间
缺点:不能立即回收对象
10. 常见GC算法总结
11. 认识V8
v8 是一款主流javascript执行引擎
v8 采用即时编译
v8 内存设限(64位系统:不超过1.5G,32操作系统:不超过800M):本身为浏览器制造的不需要太大
12. V8垃圾回收策略
采用分代回收的思想
内存分为新生代、老生代
针对不同对象采用不同算法
13. V8如何回收新生代对象
v8内存空间一分为二(新生代空间,老生代空间(多于新生代空间))
小空间用于存储新生代对象(32M | 16M)
新生代指的是存活时间较短的对象
新生代对象回收实现
1\. 回收过程采用复制算法 + 标记整理
2\. 新生代内存区分二个等大小空间
3\. 使用空间为From,空闲空间为to
4\. 活动对象存储于From空间
5\. 标记整理后将活动对象拷贝至To
6\. From 与To交换空间完成释放
回收细节说明:
1\. 拷贝过程中可能出现晋升
2\. 晋升就是将新生代对象移动至老生代
3\. 一轮GC还存活的新生代需要晋升
4\. To 空间的使用率超过25% (25% 是因为到最后From和To交换空间时,如果过多,新的对象就无法存储进来)
14. V8如何回收老生代对象
老年代对象说明:
1\. 老年代对象存放在右侧老生代区域
2\. 64位操作系统1.4G,32G操作系统700M
3\. 老年代对象就是指存活时间较长的对象
老年代对象回收实现:
1\. 主要采用标记清除、标记整理、增量标记算法
2\. 首先使用标记清除完成垃圾空间的回收
3\. 采用标记整体进行空间优化
4\. 采用增量标记进行效率优化
新老生代细节对比:
1\. 新生代区域垃圾回收使用空间换时间
2\. 老生代区域垃圾回收不适合复制算法
15. V8垃圾回收总结
16. Performance工具介绍
为什么使用Performance
1\. GC的目的时为了实现内存空间的良性循环
2\. 良性循环的基石是合理使用
3\. 时刻关注才能确定是否合理
4\. Performance 提供多种监控方式
Performance使用步骤
1\. 打开浏览器输入目标网址
2\. 进入开发人员工具面板,选择性能
3\. 开启录制功能,访问具体界面
4\. 执行用户行为,一段时间后停止录制
5\. 分析界面中记录的内存信息
17. 内存问题的体现
内存问题的外在表现:
1\. 页面出现延迟加载或经常性暂停
2\. 页面持续出现糟糕的性能
3\. 页面的性能随时间延长越来越差
18. 监控内存的几种方式
界定内存问题的标准
内存泄露:内存使用持续升高
内存膨胀:在多数设备上都存在性能问题
频繁垃圾回收: 通过内存变化图进行分析
监控内存的几种方式
1. 浏览器任务管理器
2. TimeLine时序图记录
3. 堆快照查找分离DOM
4. 判断是否存在频繁的垃圾回收
19. 任务管理器监控内存
1.shift + esc
2\. 右击 查看内存(javascript内存)
20. Timeline记录内存
21. 堆快照查找分离DOM
什么是分离DOM
1\. 界面元素存活在DOM树上
2\. 垃圾对象时的DOM节点
3\. 分离状态的DOM节点
操作:打开f12 选择Memory 第一个就是堆快照
22. 判断是否存在频繁GC
为什么确定频繁垃圾回收
1\. GC工作时应用程序是停止的
2\. 频繁且过长的GC会导致应用假死
3\. 用户使用中感知应用卡顿
23. Performance总结
chrome里的工具
24. 代码优化介绍
1. javaScript 中的内存管理自动完成
2. 执行引擎会使用不同的GC算法
3. 算法工作的目的是为了实现内存空间良性循环
4. Performance 工具监测内存变化
5. JavaScript 是单线程机制的解释型语言
如何精准测试javascript性能
1. 本质上就是采集大量的执行样本进行数学统计和分析
2. 使用基于Benchmark.js 的https://jsperf.com完成:
Jsperf使用流程
2.1 使用gitHub账号登录
2.2 填写个人信息(非必须)
2.3 填写详细的测试用例信息(title, slug)
2.4 填写准备代码(DOM操作时经常使用)
2.5 填写必要有setup 与teadown 代码
2.6 填写测试代码片段
25. 慎用全局变量
为什么要慎用:
1\. 全局变量定义在全局执行上下文,是所有作用域链的顶端
2\. 全局执行上下文一直存在于上下文执行栈,直到程序退出
3\. 如果某个局部作用域出现了同名变量则会遮蔽或污染全局
明确数据作用域的情况下,尽量用局部
全局变量特点:
1\. 全局变量挂载在window下
2\. 全局变量至少有一个引用计数
3\. 全局变量存活更久,但持续占用内存
26. 缓存全局变量
将使用中无法避免的全局变量缓存到局部
27. 通过原型对象添加附加方法
在原型对象上新增实列对象需要的方法
28. 避开闭包陷阱
闭包特点:
1\. 外部具有指向内部的引用
2\. 在 ‘外’部作用域访问‘内’部作用域的数据(内部需要return才行)
关于闭包
1\. 闭包是一种强大的语法
2\. 闭包使用不当很容易出现内存泄漏
3\. 不要为闭包而闭包
29. 避免属性访问方法使用
javascript 中的面向对象
1\. js不需要属性的访问方法,所有属性都是外部可见的
2\. 使用属性访问方法只会增加一层重定义,没有访问的控制力
30. For循环优化
var i = [1,3,4,5,6]
for (var i = 0; i<a.length; i++) {
console.log(i)
}
for (var i = 0; len = a.length; i<len; i++) { // 优于上一种
console.log(i)
}
31. 选择最优的循环方法
var arrList = new Array(1, 2, 3, 4, 5)arrList.forEach(function(item) { // 最优 console.log(item)})for (var i = arrList.length; i; i--) { //第二 console.log(arrList[i])}for (var i in arrList) { // 第三 console.log(arrList[i])}
32. 文档碎片优化节点添加
for (var i = 0; i < 10; i++) { var oP = document.createElement('p') oP.innerHTML = i document.body.appendChild(oP) } const fragEle = document.createDocumentFragment() // 优于上一种 for (var i = 0; i < 10; i++) { var oP = document.createElement('p') oP.innerHTML = i fragEle.appendChild(oP) } document.body.appendChild(fragEle)
33. 克隆优化节点操作
<p id="box1">old</p>for (var i = 0; i < 3; i++) { var oP = document.createElement('p') oP.innerHTML = i document.body.appendChild(oP) } var oldP = document.getElementById('box1')// 优于第一种 for (var i = 0; i < 3; i++) { var newP = oldP.cloneNode(false) newP.innerHTML = i document.body.appendChild(newP) }
34. 直接量替换 new Object
var a = [1, 2, 3] //优于下面一种var a1 = new Array(3)a1[0] = 1a1[1] = 2a1[2] = 3