JavaScript 性能优化
JavaScript 内存管理
- 内存管理介绍
- 内存:有可读写单元组成,表示一片可操作的空间
- 管理:人为的去操作一片空间的申请、使用和释放
- 内存管理:开发者主动申请空间、使用空间、释放空间
- 流程管理:申请–使用–释放
- JavaScript申请内存空间、使用内存空间、释放内存空间
//申请 let obj = {} //使用 obj.name = 'lg' //释放 obj = null
- JavaScript 中的垃圾回收
- JavaScript中的垃圾
JavaScript中内存的管理是自动的
对象不再被引用时就是垃圾
对象不能从根上访问到时是垃圾 - JavaScript 中的可达对象
可以访问到的对象就是可达对象(引用、作用域链)
可达的标准是从根出发是否能够被找到
JavaScript中的根可以理解为是全局变量的对象
//引用 let obj = {name: 'xm'} let ali = obj obj = null //可达 function objGroup(obj1, obj2){ obj1.next = obj2 obj2.prev = obj1 return { o1: obj1, o2: obj2 } } let obj = objGroup({name: 'obj1'},{name: 'obj2'}) console.log(obj)
- JavaScript中的垃圾
GC 算法介绍
- GC算法定义
- 定义:GC就是垃圾回收机制
- 作用:可以找到内存中的垃圾、并释放和回收空间
GC的垃圾是什么:1、程序不再需要使用对象,2、程序找不到的对象 - 算法就是工作时查找和回收立即所遵循的规则
- 常见的GC算法
- 引用计数算法
工作原理:引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是 1。如果同一个值又被赋给另一个变量,则该值的引用次数加 1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减 1。当这个值的引用次数变成 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就会回收
- 引用计数算法的优缺点
优点:1、发现垃圾时立即回收,2、最大限度减少程序暂停
缺点:1、无法回收循环引用的对象,2、资源消耗大
//对象的循环引用 function fn() { const obj1 = {} const obj2 = {} pbj1.name = obj2 obj2.name = obj1 return 'lg is a code' } fn() //obj1和obj2循环引用,导致引用计数算法无法回收这两个对象
- 标记清除算法
核心思想:分标记和清除两个阶段完成,第一阶段:遍历所有对象并标记可达对象,第二阶段:遍历所有对象清除没有标记的对象并清除第一阶段的标记,最后回收相应的空间
优点:解决对象循环引用无法回收的问题
缺点:空闲链表地址不连续,导致空间碎片化,空间无法达到最大化的使用 - 标记整理算法
标记整理算法就是标记清楚的增强:在第一阶段的标记工作完全一样,将当前可达对象标记,第二阶段不用,在第二阶段的清除之前会先做一个整理工作,移动活动对象的位置使之在位置上产生连续
- 引用计数算法
V8引擎
- 认识V8:1、目前市面上最主流的JavaScript执行引擎;2、采用即时编译,速度快;3、内存有上限(64位1.5G,32位800M);4、V8将内存空间一分为二(新生代和老生代),新生代大小为(32M|16M,对应64位和32位),新生代指存活时间较短的对象(局部变量),老生代大小为(1.4G|700M,对应64位和32位)
- V8垃圾回收策略
- 因为内存是有上限的,所以采用分代回收的思想,内存分为新生代和老生代,针对不同代的对象采用不同算法
- V8常用的GC算法:分代回收、空间复制、标记清除、标记整理、标记增量
- V8新生代的垃圾回收
算法:复制算法和标记整理算法
垃圾回收过程:新生代内存分为两个等大的区域,使用空间为from,空闲空间为to,活动对象存储于from空间,标记整理后将活动对象拷贝至to空间,from与to空间交换完成后释放from空间。
回收细节说明:拷贝过程可能出现晋升(新生代对象移动至老生代,一轮GC还存活的新生代对象需要晋升或者to空间的使用率超过了25%) - V8老生代的垃圾回收
老生代对象:存放在老生代区,老生代对象就是指存活时间较长的对象,
算法:标记清除+标记整理+增量标记
垃圾回收过程:首先使用标记清除算法完成垃圾空间回收,随后采用标记整理算法进行空间优化,最后采用增量标记进行效率优化
细节对比:新生代垃圾回收用空间换时间,老年代不适合
标记增量如何优化垃圾回收:将垃圾回收分成几小步,让垃圾回收和程序执行交替执行。
- V8垃圾回收总结
- V8是当前主流的JavaScript执行引擎
- V8内部内存设置上限
- V8采用基于分代回收思想实现垃圾回收
- V8 内存分为新生代和老生代
- V8 垃圾回收常见的GC算法
Performance工具
- 基本介绍
- 为什么使用这个工具:GC的目的是为了实现内存空间的良性循环,良性循环的基石是合理使用,所以必须时刻关注才能确定是否合理,通过Performance就可以实现这种监控。
- 内存问题的体现
- 页面出现延迟加载或经常性暂停
- 页面出现持续性糟糕性能的表现
- 页面的性能随时间的延长越来越差
- 监控内存的几种方式
-
三种内存问题的界定
内存泄漏:内存使用的持续升高
内存膨胀:在多数设备上都存在的性能问题,才是内存膨胀
频繁垃圾回收:通过内存变化图分析 -
监控内存的方式
浏览器任务管理器
Timeline 时序图记录
堆快照查找分离DOM
判断是否存在频繁地垃圾回收 -
任务管理器监控内存
shift+esc调用浏览器的任务管理器 -
Timeline 记录内存变化
-
堆快照功能查找分离DOM
工作原理:找到当前的JS堆,进行一个照片的留存,找到分离DOM并删除
垃圾DOM:从DOM树上脱离且没有被引用
分离DOM:从DOM树上脱离但是在JS代码中仍然被引用 -
判断是否存在频繁地垃圾回收
垃圾回收的缺点:GC工作时应用程序是停止的,频繁且过长的GC会导致应用假死,用户使用中会感知应用卡顿。
两种方式:1、Timeline中频繁上升下降,2、任务管理器中数据频繁地增加减少
-
- Performance总结
1、Chrome提供的工具,通过使用该工具可以监控程序对内存的使用,以发现内存使用的问题并优化程序