V8引擎内存优化+运行性能优化

在我前面的文章中,有写到 V8 的内存管理机制,其中 就有 标记整理 算法

但是如果有同学 对js 语言底层的实现 深入了解的话,肯定会疑惑,为什么需要整理内存,获得一个大的连续空间呢?

  1. js 是一个 万物皆对象的语言,functon,number,string 等等都是对象,就连 Array 都是对象
  2. 而理论上来说,一个对象是 hash 表结构存储数据的
  3. 而hash 表结构存储数据的话,就意味着 他其实不需要 多么大的连续空间,就能够存储很多很多的数据

所以说,这里需要更加深入地去了解 V8 内部到底是怎么处理 一个 对象数据的

1、一个普通的对象内部存储方式

v8引擎 为了增加读取数据的性能考虑,其实做了很多很多的优化

  1. 在一个普通的对象之中,存放属性分为 两个区域,一个叫做快区域 名字叫做 elements ,一个叫做慢区域 叫做 properties
  2. 快区域是使用 连续内存进行存储的,而慢区域则是 使用hash 表结构存储的
  3. 当读取一个属性的时候,v8 先是在 快区域中寻找,没找到才会去 慢区域寻找
  4. 如下面的内容所示,只要是 数字类型的,就被放在了 elements 里面,而 其他类型的,被放在了 properties 里面
  5. 而数组类型的 ,自然在大多数情况下都被放在了 elements 里面,也就是说,在 js 里,其实数组 还真是被放在连续内存里面的
        function FS(fast, slow) {
            this.fast2slow = {}
            for (let i = 0; i < fast; i ++) {
                this[i] = 'fast'
            }
            for (let i = 0; i < slow; i++) {
                this[`slow${i}`] = slow
            }
        }
        var fs = new FS(10, 10)

在某些文章中,有写到 当 数字大到一定程度的时候,数组 的存储结构也会变成一个 hash 表

        function FS1(fast, slow) {
            this.fast2slow = new Array(10)
        }
        function FS2(fast, slow) {
            this.fast2slow = new Array(100000000)
        }
        var fs1 = new FS1()
        var fs2 = new FS2()

  1. 在 fs1 中,可以很明显的看到 elements 里面已经没有再存储数据了
  2. 在 fs2 中,则还有 数据在存储

2、隐藏类

  1. 众所周知的是,js 是一门 动态语言类型,不像 java 语言那样,有着静态类型
  2. 但是 在这方面 就会出现一个问题,那就是读取数据的时候不如静态语言快速
  3. 静态语言中的 类 会对 某一个属性 进行规定,然后快速地查找到这个值,而不是像 动态语言一样,需要遍历一边所有的属性因为 V8 引擎不知道 开发者内部到底有没有这个类
  4. 那么为了这个,V8 引擎为此又做出了什么优化呢?
  1. 在一个对象创建了之后,V8 引擎会为其分配一个 隐藏类
  2. 就像是 静态语言的类一样,可以帮助 V8引擎 快速地定位到一个元素的所在
  3. 在类似的数据结构中,V8 引擎会为其分配相同的类,也就是 相同的属性名称,相同的属性数量
  4. 有了隐藏类之后,那么当 V8 访问某个对象中的某个属性时,就会先去隐藏类中查找该属性相对于它的对象的偏移量,有了偏移量和属性类型,V8 就可以直接去内存中取出对于的属性值,而不需要经历一系列的查找过程,那么这就大大提升了 V8 查找对象的效率

3、优化

所以了解了这个之后,又有什么用呢?

  1. 使用 typeScript 确实在某种意义上能够帮助我们加快 js 的运行速度
  2. 不要随便地使用 delete 或者 增加一个属性,因为这样会导致 隐藏类失效而 重新 构建一个新的隐藏类
  3. 使用字面量初始化对象时,要保证属性的顺序是一致的,
  4. 例如 var a = {x: 1, y: 2}; b = {y: 1, x : 2} 这样会导致 创建两个 隐藏类

学习自 李兵 老师的 《图解 Google V8》

4、其他的优化方案

  1. 慎用全局变量,因为会顺着作用域链查找变量,查找的层级越高,速度就越慢
  2. 缓存全局变量,例如: 在 一个函数内部,如果需要调用 document.createElement 等函数的时候,先将var doc = document 缓存起来,这样 doc 就不是全局变量了,而是 在 同一个 作用域中的值 
  3. 通过原型链增加方法
  4. 创建 多个 dom 节点的时候,可以使用 document.createElementFrment 或者 先使用字符串拼接,再一次性 innerhtml
  5. 使用 字面量的 方法创建一个 数组或者对象,而不是使用 new Object 或者 new Array 
  6. 在数组的循环中 forEach 的 运行速度 > for > for in

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值