JavaScript 垃圾回收和代码优化实例

JavaScript 性能优化

内容概要

1.内存管理
2.垃圾回收与常见GC算法
3.V8引擎的垃圾回收
4.Performance 工具
5.代码优化实例

JavaScript 内存管理

1.内存:由可读写单元组成,表示一片可操作空间
2.管理:人为的去操作一片空间的申请、使用和释放
3.内存管理:开发者主动申请空间、使用空间、释放空间
4.管理流程:申请-使用-释放

// 申请
let obj = {}
//使用
obj.name = 'lg'
//释放
obj = null

JavaScript 中的垃圾回收

1.JavaScript 中的内存管理是自动的
2.对象不再被引用时就是垃圾
3.对象不能从根上访问到时垃圾

JavaScript 中的可达对象

1.可以访问到的对象就是可达对象(引用、作用域链)
2.可达的标准就是从根出发是否能够被找到
3.JavaScript中的根就可以理解为是全局变量对象

GC定义与作用

1.GC就是垃圾回收机制的简写
2.GC可以找到内存中的垃圾、并释放和回收空间
(1)程序中不再需要使用的对象

function func(){
    name = 'lg'
    return `${name} is a coder`
}
func()

(2)程序中不能再访问到的对象`

function func(){
    const name = 'lg'
    return `${name} is a coder`
}
func()

3.GC是一种机制,垃圾回收器完成具体的工作
4.工作的内容就是查找垃圾释放空间、回收空间
5.算法就是工作时查找和回收所遵循的规则
6.常见GC算法
(1)引用计数
(2)标记清除
(3)标记整理
(4)分代回收

引用计算实现原理

1.核心思想:设置引用数,判断当前引用数是否为0
2.引用计数器
3.引用关系改变时修改引用数字
4.引用数字为0时立即回收

function fn(){
    num1 = 1 
    num2 = 2
    //由于num1、num2没有设置关键字  所以挂载在window对象下的 引用计数不是0
    // 如果加上const关键字声明 只能在这个函数作用域内使用 
    //一旦调用结束 我们从全局的地方触发 就不能找到num1、num2 那么它们的引用计算就会变成0 GC就是当成垃圾回收
}
fn()

引用计数算法优缺点

优点:
1.发现垃圾时立即回收
2.最大限度减少程序暂停
缺点:
1.无法回收循环引用的对象

function init(){
    const obj1 = {}
    const obj2 = {}
    obj1.name = obj2
    obj2.name = obj1
}
init()

2.时间开销大
引用计数算法

标记清除算法

1.核心思想:分标记和清除两个阶段完成
2.遍历所有对象,找标记活动对象
3.遍历所有对象,清除没有标记对象
4.回收相应的空间
优点:
1.相对引用计数来说 循环引用不能回收的问题
缺点:
1.垃圾回收时 空间碎片化 不能让空间得到最大的使用
2.不能立即回收垃圾
标记清除算法

标记整理算法原理

1.标记整理可以看做是标记清除的增强
2.标记阶段的操作和标记清除一致
3.清除阶段会先执行整理,移动对象位置
4.不能立即回收垃圾
标记整理算法前
标记整理算法中
标记整理算法后

认识V8

1.V8是一款主流的JavaScript执行引擎
2.V8采用即时编译
3.V8内存设限
4.内存分为新生代和老生代

V8垃圾回收策略

1.分代回收
2.空间复制
3.标记清除
4.标记整理
5.标记增量

V8如何回收新生代对象

1.V8内存分配
(1)V8内存空间一分为二
(2)小空间用于存储新生代对象(32M|16M)
(3)新生代指的是存活时间较短的对象
2.新生代对象回收实现
(1)回收过程采用复制算法+标记整理
(2)新生代内存区分为两个等大小空间
(3)使用空间为From,空闲空间为To
(4)活动对象存储于From空间
(5)标记整理后将活动对象拷贝至To
(6)From与To交换空间完成释放
3.回收细节说明
(1)拷贝过程中可能出现晋升
(2)晋升就是将新生代对象移至老生代
(3)一轮GC还存活的新生代需要晋升
(4)To空间的使用率超过25%

V8如何回收老生代对象

1.老生代对象存放在右侧老生代区域
2.64位操作系统1.4G,32操作系统700M
3.老生代对象就是指存活时间较长的对象
4.老生代对象回收实现
(1)主要采用标记清除、标记整理、增量标记算法
(2)首先使用标记清除完成垃圾空间的回收
(3)采用标记整理进行空间优化
(4)采用增量标记进行效率优化
5.细节对比
(1)新生代区域垃圾回收使用空间换时间(空间较小)
(2)老生代区域垃圾回收不适合复制算法(空间大、数据多)

Performance 工具介绍

1.GC的目的是为了实现内存空间的良性循环
2.良性循环的基石是合理使用
3.时刻关注才能确定是否合理
4.Performance提供多种监控方式

内存问题的外在表现

1.页面出现延迟加载或经常性暂停
2.页面持续性出现糟糕的性能
3.页面的性能随时间延长越来越差

监控内存的几种方式

1.浏览器任务管理器 (shift+esc)
(1)可以监控程序运行时DOM与JS堆分别占据的内存空间变化
2.TimeLine时序图记录
(1)可以获取程序运行中JS堆内存的走势图和是否存在频繁的垃圾回收
3.堆快照查找分离DOM

什么是分离DOM

1.界面元素存活在DOM树上
2.垃圾对象时的DOM节点
3.分离状态的DOM节点
4.在界面上不体现 在内存中却真实存在

为什么确定频繁垃圾回收

1.GC工作时应用程序是停止的
2.频繁且过长的GC会导致应用假死
3.用户使用中感知应用卡顿

慎用全局变量

1.全局变量定义在全局执行上下文,是所有作用域链的顶端
2.全局执行上下文一直存在于上下文执行栈,直到程序退出
3.如果某个局部作用域出现了同名变量则会遮蔽或污染全局

缓存全局变量

1.执行效率会更快

function getBtn1() {
    let oBtn1 = document.getElementById('btn1')
    let oBtn2 = document.getElementById('btn2')
    let oBtn3 = document.getElementById('btn3')
    let oBtn4 = document.getElementById('btn4')
}
function getBtn2() {
    let obj = document
    let oBtn1 = obj.getElementById('btn1')
    let oBtn2 = obj.getElementById('btn2')
    let oBtn3 = obj.getElementById('btn3')
    let oBtn4 = obj.getElementById('btn4')
}

通过原型对象添加附加方法

对象添加方法

避开闭包陷阱

function foo(){
    var el = document.getElementById('btn') 
    el.onclick = function() {
        console.log(el.id)
    }
    el = null
    //如果dom节点在我们程序中消失了 dom的引用就不存在了
    //但是el对之前的dom还是有引用的 垃圾回收机制并不会对它回收 就会导致内存泄漏
    //如果加上 el = null 我们代码的引用也就消失了
}

避免属性访问方法使用

属性访问方法

For循环优化

var aBtns = document.getElementsByClassName('btn')
for (let index = 0; index < aBtns.length; index++) {
    console.log(index)
}
// 优化
for (let index = 0; len = aBtns.length index < len; index++) {
    console.log(index)
}

选择最优的循环方法

循环

文档碎片优化节点添加

文档碎片

克隆优化节点操作

克隆优化

直接量替换new Object

替换new Object

减少判断层级

判断层级

减少作用域链查找层级

作用域查找

减少数据读取次数

数据读取次数
1.索引值要频繁访问的时候 需要提前存储起来 节约查找时间 使速度更快
2.这样的快建立在消耗内存空间的情况下

字面量与构造式

let test = () => {
    let obj = new Object() // 需要调用一个函数
    obj.name = 'zce'
    obj.age = 38
    obj.slogan = '我为前端而活'
    return obj
}
let test = () => {
    let obj = {  // 直接开辟一个空间存储
        name:'zce',
        age:38,
        slogan:'我为前端而活'
    }
    return obj
}
console.log(test())

// 基本类型创建时 字面量形式要远远高于构造形式
var str1 = 'zce时刻都能'
var str2 = new String('zce时刻都能') 

console.log(str1)
console.log(str2)

1.字面量速度要快于构造式

减少声明及语句

减少声明语句

采用事件绑定

事件委托

1.在元素非常多的情况下 for循环一个个绑定点击事件肯定是要比 事件委托要慢许多的

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值