Part1-2-3 JavaScript 性能优化

 JavaScript 内存管理

申请内存空间

使用内存空间

释放内存空间

Part1-2-3 JavaScript 性能优化_第1张图片

 

常见GC算法

引用计数

标记清除

标记整理

分代回收

 

引用计数算法

核心思想:设置引用数,判断当前引用数是否为0

引用计数器

引用关系改变时,修改引用数字

引用数字为0时立即回收

 

引用计数算法优点

  • 发现垃圾时立即回收

             根据当前引用数是否为0,来决定这个对象是不是垃圾,如果判定为垃圾,立即进行释放

  • 最大限度减少程序暂停

             应用程序在执行过程中,必然会对内存进行消耗,而内存空间是有上限的,当内存快被占满时,引用计数会找到引用数为0的对象,进行释放

 

引用计数算法缺点

  • 无法回收循环引用的对象

       

Part1-2-3 JavaScript 性能优化_第2张图片

上图代码中,当代码执行完后,虽然在全局中,已经找不到obj1和obj2,但是在函数内,由于相互引用,所以obj1和obj2的引用计数就不是为0,造成引用计数算法无法回收这2个对象的内存空间,造成了内存空间浪费。

       

  • 时间开销大

              因为当前的引用计数需要去维护一个数值的变化,所以在这种情况下,要时刻监控当前对象的引用数值是否需要修改,对象引用计数的修改就需要消耗时间,需要修改的对象越多,则需要的时间也就越多。

 

标记清除算法

核心思想:分标记和清除二个阶段完成

遍历所有对象找标记活动对象

遍历所有对象清除没有标记对象

回收相应的空间

 

  1. 遍历所有对象找到活动对象进行标记。
  2. 遍历所有对象找到没有标记的对象,进行清除,同时去除所有对象的标记,以便下一次正常的工作。

通过2次的遍历行为,把当前的垃圾空间进行回收,最终交给空闲列表进行维护。

 

标记清除算法优点

解决了引用计数无法回收循环引用对象的问题

 

标记清除算法缺点

会造成空间碎片化。

由于所回收的对象在内存地址上是不连续的,因此造成空闲区间也是不连续的。

Part1-2-3 JavaScript 性能优化_第3张图片

 

标记整理算法原理

标记整理算法可以看做是标记清除算法的增强

标记阶段的操作和标记清除算法一致

清除阶段会先执行整理,移动对象位置,让地址产生连续

 

标记整理算法图示

会先把活动对象进行标记,然后进行整理,将活动对象进行移动,在地址上变成连续的位置,

然后将活动对象整理后以外的区域进行整体回收,

这样就使得回收后的空间是连续的

 

Part1-2-3 JavaScript 性能优化_第4张图片

 

2

Part1-2-3 JavaScript 性能优化_第5张图片

 

 

认识V8

V8是一款主流的 JavaScript 执行引擎, Chrome浏览器、NodeJs都在使用

V8采用即时编译,将源码翻译成当前可以直接执行的机器码,使得执行速度很快

V8内存设限,64位操作系统不超过1.5G, 32位操作系统不超过800M

 

V8垃圾回收策略

采用分代回收的思想

内存分为新生代、老生代

针对不同对象采用不同算法

 

V8垃圾回收策略图示

Part1-2-3 JavaScript 性能优化_第6张图片

 

V8中常用GC算法

分代回收

空间复制

标记清除

标记整理

标记增量

 

V8如何回收新生代对象

V8内存分配

Part1-2-3 JavaScript 性能优化_第7张图片

 

V8内存空间一分为二,左侧用于存储新生代对象

小空间用于存储新生代对象 (64位操作系统大小是 32M | 32位操作系统大小是 16M)

新生代指的是存活时间较短的对象,如函数内声明的对象

 

新生代对象回收实现

回收过程采用空间复制算法 + 标记整理

新生代内存区分为二个等大小空间

使用空间为 From, 空闲空间为 To

活动对象存储于 From 空间

标记整理后将活动对象拷贝至 To

From 与 To 交换空间完成释放

 

回收细节说明

拷贝过程中可能出现晋升,拷贝过程中如果某个变量所指引的空间在当前的老生代对象里也会出现,这时候就会出现晋升操作

晋升就是指将新生代对象移动至老生代进行存储

一轮 GC后 还存活的新生代需要晋升

To 空间的使用率超过 25%时,将活动对象移动至老生代进行存储

 

老生代对象说明

老生代对象存放在右侧老生代区域

内存大小限制:64位操作系统 1.4G , 32位操作系统  700M

老生代对象就是指存活时间较长的对象:如果全局对象,闭包内的对象

 

老生代对象回收实现

主要采用标记清除、标记整理、增量标记算法

首先使用标记清除完成垃圾空间的回收

采用标记整理进行空间优化:当有新生代对象往老生代存储区域进行移动的时候,而这时老生代存储空间不足以存放新生代对象时,这时候就会触发标记整理

采用增量标记进行效率优化

 

增量标记如何优化垃圾回收

当垃圾回收进行工作时,会阻塞 JavaScript 程序执行。

将我们一整段的垃圾回收操作,拆分成多个小步,组合着去完成当前整个垃圾回收。

实现垃圾回收和程序执行交替完成,这样所带来的时间消耗会更加合理一些。

Part1-2-3 JavaScript 性能优化_第8张图片

 

细节对比

新生代区域垃圾回收使用空间换时间

老生代由于存储空间大,因此老生代区域垃圾回收不适合不适合复制算法

 

Performance 使用步骤

打开浏览器输入目标网址

进入开发人员工具面板,选择性能

开启录制功能,访问具体界面

执行用户行为,一段时间后停止录制

分析界面中记录的内存信息

 

内存问题的外在表现

页面出现延迟加载或经常性暂停:与GC存在着频繁地垃圾回收操作相关,之所以会存在频繁垃圾回收操作,说明是有一些代码瞬间让内存爆掉了,需要去进行定位。

页面持续性出现糟糕性能表现:说明存在着内存膨胀,当前界面为了达到最佳的使用速度,去申请了一定的内存空间,而这所需要的的内存空间大小远超过了当前设备所能提供的内存大小

页面的性能随时间延长越来越差: 说明存在着内存泄漏

 

监控内存的几种方式

浏览器任务管理器

Timeline 时序图记录

堆快照查找分离 DOM

判断是否存在频繁的垃圾回收

 

为什么确定频繁垃圾回收

GC 工作时应用程序是停止的

频繁且过长的 GC 会导致应用假死

用户使用中感知应用卡顿

 

确定频繁的垃圾回收

Timeline 中频繁的上升下降

任务管理器中数据频繁的增加减小

 

代码优化

慎用全局变量

缓存全局变量




  
  
  缓存全局变量


  
  
  
  
  

1111

222

333

 

通过原型新增方法

在原型对象上新增实例对象需要的方法


var fn1 = function() {
  this.foo = function() {
    console.log(11111)
  }
}

let f1 = new fn1()


var fn2 = function() {}
fn2.prototype.foo = function() {
  console.log(11111)
}

let f2 = new fn2()

 

 

 

 

 

 

 

1

 

你可能感兴趣的:(大前端学习笔记)