JavaScript性能优化1

本文介绍了JavaScript的内存管理,包括自动垃圾回收机制、可达对象的概念以及常见的GC算法,如引用计数、标记清除和标记整理。重点讲解了V8引擎的内存限制、垃圾回收策略和新生代、老生代对象的回收细节。此外,还探讨了如何通过性能工具监控内存问题,并分享了代码优化的实践建议,如慎用全局变量、缓存全局变量等。
摘要由CSDN通过智能技术生成

JavaScript内存管理

内存管理介绍

  • 内存:由可读写单元组成,表示一片可操作控件
  • 管理:认为的去操作一盘控件的申请,使用和释放
  • 内存管理:开发者主动申请空间,使用空间,释放空间
  • 管理流程:申请-使用-释放

JavaScript中的内存管理

  • 申请内存空间
  • 使用内存空间
  • 释放内存空间
// 演示内存的生命周期
// 申请
let obj = {}
// 使用
obj.name = "lg"
// 释放
obj = null

JavaScript中的垃圾回收

  • JavaScript中的内存管理是自动的=>每当我们创建一个对象,数组或者函数的时候,系统会自动的去分配相应的内存空间,后续程序代码在执行的过程中,如果通过引用关系无法再找到某些对象的时候,name这些对象就会被看做是垃圾
  • 对象不再被引用时是垃圾
  • 对象不能从根上访问到时是垃圾
  • 垃圾回收机制的核心是可达对象和引用

JavaScript中的可达对象

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

GC算法的介绍

GC定义和作用

  • GC就是垃圾回收机制的简写
  • GC可以找到内存中的垃圾,并释放和回收空间

GC里的垃圾是什么

  • 程序中不再需要使用的对象
function func() {
    name = "lg"
}
func()
  • 程序中不能再访问到的对象
function func() {
    const name = "lg"
}
func()

常见的GC算法

  • 引用计数
  • 标记清除(v8中使用)
  • 标记整理(v8中使用)
  • 分代回收

引用计数算法

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

注意点

  1. 全局变量是挂载到window下面的,他们的引用计数一直不为0
  2. 在作用域中定义的变量虽然在函数执行完毕后,这些变量就不是可达对象了,但如果这些变量相互引用,则这些变量的引用计数不为0,不会被回收
引用计数算法优点
  • 发现垃圾时(引用计数为0)立即回收
  • 最大限度减少程序暂停=>当内存即将爆满的时候,引用计数就会立马去找到那些引用计数为0的数值空间,对其进行释放,保证了当前内存不会有爆满的时候
引用计数算法的缺点
  • 无法回收循环引用的对象
function fn() {
   
    const obj1 = {
   }
    const obj2 = {
   }
    obj1.name = obj2 //循环引用
    obj2.name = obj1
}
fn()
/* 
函数执行完毕后,它所在的空间肯定会涉及到回收的情况,比如obj1,obj2,他们都不是可达对象了,
但他们之间是相互引用,obj1和obj2的引用计数器数值不为0,引用计数器下的GC不能对obj1,obj2的两个空间进行回收
*/
  • 时间开销大=>引用计数需要维护一个数值的变化,时刻去监控当前对象的引用数值是否需要修改,对象本身的修改就需要时间

标记清除算法

  • 核心思想:分标记和清除两个阶段完成
  • 遍历所有对象找到标记活动对象==(和可达对象概念相同)==
  • 遍历所有对象,清除没有标记对象
  • 回收相应的空间,回收的那些空间交给空闲链表维护,当系统再次申请空间时,优先从空闲链表分配相应空间

注意点:可达对象都会打上标记,不可达对象都会取消标记

标记清除算法优点
  • 可以回收循环引用的对象=>当一个函数中的局部变量相互引用,当函数执行完毕后,虽然函数中的变量是相互引用的,但他们已经不是可达对象了,即取消了标记,下次垃圾回收时(不像引用计数算法当计数器为0就立即回收),会把该对象(垃圾)回收
标记清除法缺点
  • 空间碎片化,不能使回收的空间得到最大化的使用>当前所回收的垃圾对象在地址上本身是不连续的,由于这种不连续造成在回收之后在空闲链表中分散在各个角落(a1,a2,a3…空间,她们是各自独立,分散的),后续系统要申请空间,优先从从空闲链表分配相应的控件,当申请的空间大小正好和某一个散落在空闲列表的空间大小相同,则可以正常使用,否则(大小不一致),则不能正常使用

标记整理算法的原理

  • 标记整理可以看做是标记清除的增强
  • 标记阶段的操作和标记清除一致
  • 但是标记清除阶段之前会先执行整理,移动对象位置(原本的对象在地址上是不连续,将他们移动位置,变成连续)
  • 地址不连续就是说存储的空间不挨着
  1. 回收前
    在这里插入图片描述
  2. 回收后=>非活动对象清除后的空间(已经是整理后的,连续的,交给空闲链表,所以空闲链表的空间也是连续的)
    在这里插入图片描述
标记整理算法的优点
  • 空闲链表中的空间时连续的,整块可用,系统申请空间时,只要不超过空间链表的整个大小,空闲链表就会分配相应的空间大小(切割)

常见GC算法小结

引用计数优缺点
  • 可以及时回收垃圾对象
  • 减少程序卡顿事件
  • 无法回收循环引用的对象
  • 资源消耗较大(实时监控计数器)
标记清除优缺点
  • 可以回收循环引用的对象
  • 容易产生碎片化空间,浪费空间
  • 不会立即回收垃圾对象(回收的过程,程序是暂停的)
标记整理优缺点
  • 减少碎片化空间
  • 不会立即回收垃圾对象

认识V8

V8基本知识

  • V8是一款主流的JavaScript执行引擎
  • V8采用即时编译(之前很多js引擎都是将源代码先转成字节码,然后才能执行),V8直接将源码翻译成我们当前直接执行的机器码,所以速度是非常快的
  • v8内存设限(在64位操作系统的上限是1.5G;32位操作系统是800M),具体原因如下
  1. v8引擎本身就是为了浏览器而去制造的,所以现存的内存大小对于网页应用是足够使用的
  2. v8内部实现的垃圾回水机制也决定了它采用这个设置是合理的,当垃圾内存达到1.5G的时候,如果V8采用增量标记的算法进行垃圾回收,则需要消耗50毫秒,如果采用非增量(突破1.5G继续增加内存)标记的形式去回收,则需要1s,从用户体验的角度来说,1s算很长时间了(标记的过程和程序是间隔连续完成的(间隔时间很短),垃圾清除的过程整个程序停下来,如果超过1s停顿,就会造成用户视觉上的卡顿)

V8垃圾回收策略

背景(重要!!!)

在程序的使用过程中,我们会用到很多的数据,这些数据可以分为原始数据和对象类型数据(引用类型数据),原始数据是由程序的语言(js)自身来进行控制的,所以在这里我们所说道的回收主要指的是存在堆区域里的引用类型数据,这个过程离不开内存操作数据,

策略

  • 采用分带回收的思想
  • 内存分为新生代,老生代存储区
  • 针对不同的分带(里面是不同的对象)采用不同算法

V8中常用的GC算法

  • 分代回收
  • 空间复制
  • 标记清除
  • 标记整理
  • 标记增量

V8如何回收新生代对象

在这里插入图片描述

V8内存分配
  • v8内存一分为二
  • 小空间用于存储新生代对象(64位系统分32M|32为系统分16M)
  • 大空间用于存储老年代对象(1.4G|700M)
  • 新生代指的就是存活时间较短的对象=>局部作用域中的某些变量(全局作用域中的变量不是新生代对象,因为它们的存活时间较长,要等整个程序完全退出才会回收)
  • 老生代对象就是指存活时间较长的对象(全局对象,闭包中存储的数据)
新生代对象回收实现
  • 回收过程采用复制算法+标记整理
  • 新生代内存区分为两个等大小空间(上面的From+To区域)
  • From:使用空间 To:空闲空间 =>代码在执行的时候,如果需要申请空间,首先会将所有的变量对象分配至From空间,这个时候,To空间处于空闲状态
  • 对象存储于From空间=>当From空间应用到一定的程度后,就会触发GC操作,就会采用标志整理来对From空间的对象进行标记(函数执行完毕后,如果还是活动对象则标记,将这些活动对象拷贝到To区域,非活动对象则不会标记,也就不会被拷贝到To区域,To区域保证是不会被回收的活动对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值