javaScript性能优化
1.内存管理
function fn(){
arrList=[]
arrList[10000000]="lg is a coder"
}
fn()
- 内存:由可读写单元组成,表示一片可操作的空间
- 管理:人为的去操作一片空间的申请,使用和释放
- 内存管理:开发者主动申请空间,使用空间和释放空间
- 步骤:申请使用和释放
js中的内存管理
-
申请内存空间
let obj={}
-
使用内存空间
obj.name='lg'
-
释放内存空间
obj=null
2.垃圾回收与常见的GC算法
javaScript中的垃圾回收
-
js中的内存管理是自动的
-
对象不再被引用的时候
-
对象不能从根上访问
-
javaScript中的可达的对象
-
可以访问到的对象就是可达的对象
-
可达的标准就是从根出发上市否能够找到
-
根就是全局变量
let obj={ name:'xiaoming'} // 在根上可以访问到 let ali=obj obj=null // 小明也是可达的
-
GC算法
-
GC定义与作用
- GC是垃圾回收的简写
- GC可以找到内存中的垃圾,并释放和回收 空间
- 算法就是工作时查找和回收所遵循的规则
-
常见的GC算法
- 引用技术
- 标记清除
- 标记整理
- 分代回收
-
引用计数算法的实现原
-
核心思想:设置引用数,判断当前引用数是否为0,当引用数为0回收
-
引用计数器:
-
引用关系改变时修改引用数字
-
引用数字为0的时候进行回收
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() //函数执行完num1 num2被清空
-
优点,发现垃圾时候立即进行回收,最大限度减少程序的暂停。
-
缺点,无法收回循环引用的对象,时间开销大。
function fn() { const obj1 = { } const obj2 = { } obj1.name = obj2 obj2.name = obj1 return 'lg is a coder' } fn() // 互相引用的垃圾不能被清除
-
-
标记清除算法实现原理
-
核心思想:分为标记和清除两个阶段
-
遍历所有对象找标记活动对象
-
遍历所有对象清除没有标记对象
-
回收相应的空间
-
循环找到可达对象,标记完成之后,找到没有标记的可达对象然后回收,最后会放到一个内存队列
-
优点:可以解决对象循环引用的操作
-
缺点:释放的地址不连续,会导致空间碎片化
-
-
标记整理算法原理
- 标记整理算法是标记清除算法的增强
- 标记阶段的操作和标记清除一致
- 清除阶段会先执行整理,移动对象位置
3.V8引擎的垃圾回收
1.认识V8
- V8是一款主流的javaScript的执行引擎
- V8采用的是即时编译
- V8内存设限
- 64位1.4G,32 位0.7G;
- 64位新生代的空间为64M 老生代的为1400M,32位新生代为16M,老生代为700M
2.V8的垃圾回收策略
- 采用分代回收的思想
- 内存分为新生代和老生代
- 针对不同的对象采用不同的算法
3.V8中常见的GC算法
- 分代回收
- 空间复制
- 标记清除
- 标记整理
- 标记增量
4.V8内存分配
-
V8的内存一分为二
-
小空间用于新生代对象(32M|16M)
-
新生代对象指存活时间较短的对象
-
新生代对象回收的实现
-
回收过程采用空间复制算法+标记整理算法
-
新生代的内存分为两个等大小的空间
-
使用空间为From,空闲空间为To(牺牲空间来获取时间)
-
活动对象存于From空间,标记整理后存放在To空间
-
From与To交换完成进行空间释放
晋升效果
- 拷贝的过程中可能会出现晋升的效果
- 晋升就是将新生代对象移动至老生代
- 一般一轮GC过后还存活的新生代就晋升
- To的空间使用率超过25%也会晋升
-
-
老生代对象回收说明
-
主要采用标记清除,标记整理,增量标记的算法
-
首先使用标记清除完成垃圾空间的回收(速度)
-
采用标记整理进行空间优化
-
采用增量标记进行效率优化
————增量标记
增量标记其实就是 每次处理一部分对象,
-
核心思想:垃圾永远都是垃圾
新生对象不是垃圾
-
标记阶段
-
清理过程
-
-
4.Pereformance工具
1.Performance使用步骤
- 打开浏览器输入网址
- 进入开发人员工具面版,选择性能
- 开启录制功能,访问具体页面
- 执行用户行为,一段时间后停止录制
- 分析界面中的内存信息
2.内存问题
- 页面延迟加载或经常性暂停
- 页面持续性出现糟糕的性能
- 页面的性能随着使用的时间延长越来越长
3.监控内存的几种方式
- 内存泄露:内存使用持续升高
- 内存膨胀:在多数设备上都存在性能问题
- 频繁进行垃圾回收:通过内存变化图进行分析
- 浏览器任务管理器
- Timeline时序图记录
- 堆快照查找分类DOM
- 判断是否存在频繁的垃圾回收
任务管理器监控内存
- shift+ESC调出浏览器任务管理器
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MiAZP079-1608648108033)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\1608474344721.png)]
- 第一列是DOM所占据的内存,
TimeLine时序图记录内存
- F12控制台,选择性能 开始记录
- 根据一个时间段的界面生成时序图
堆快照查找分离DOM
- 界面元素存活在DOM树上
- 垃圾对象时的DOM节点
- 分离状态的DOM节点
- 垃圾DOM:没有在DOM树上且没有被jS代码引用
- 分离DOM:没有在DOM树上 被JS代码引用
- 内存面板:堆快照,找到分离DOM,一般直接为Null可以消除分离DOM
判断是否存在频繁垃圾回收
原因:
- GC工作时候应用程序是停止的
- 频繁且过长的GC会导致应用程序假死
- 用户使用中会感觉卡顿
找问题
- Timeline中频烦的上升或下降,或者长时间在正常下水平时候,时间线一段时间处于水平一下(长时间的GC)
- 任务管理器中的数据频繁增加或者减小
5.代码优化实例
1.jsperf使用
-
https://jsperf.com 在线代码片段性能测试工具
https://jsbench.me/
-
在指定环境下运行多次,然后输入对比结果
2.慎用全局变量
- 全局变量定义在全局执行上下文,是所有作用域链顶端
- 全局执行上下文一直存在于上下文执行栈,直到程序退出
- 如果某个局部作用域出现同名变量则会遮蔽或者全局污染
//全局
var i, str = ''
for (i = 0; i < 1000; i++) {
str += i
}
//局部
for (let i = 0; i < 1000; i++) {
let str = ''
str += i
}
-
jsPerf使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gKOiJQRg-1608648108034)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\1608550858391.png)]
3.缓存全局变量
-
将使用中无法避免的全局变量缓存到局部中
-
案例
<!DOCTYPE html> <html lang="en"> <head> <meta