大前端— js 内存

1.可达的内存

v8 本身有内存回收机制,并且会回收 所有不可达的内存,那么什么是 可达的内存呢?

从全局执行上下文出发,能找到的,就被认为是可达的

如下所示, obj 就是 可达的,而 obj1 obj2 就是不可达的

var obj = {parent: obj}

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

而如下所示,user 就是可达的,name 属性是不可达的

const user = {age: 1}
const list = [user.age] // 引用 + 1

function fn() {
  const name = 'jack'
}
fn()

2. v8 中的内存机制

  64位 1.5G 32位 800M

  新生代 老生代
内存大小(64位) 32M 14G
内存大小(32位) 16M 700M
执行的操作 复制、标记整理 标记清除、标记整理、增量标记
  1. 其中新生代 还分为 两个区域,一个是from,一个是to,专门用来执行 复制 操作
  2. 所谓的复制 操作 指的是 在 from 区域 中的内存要 用完之前,就会把 当前 可达的内存 复制一份,到 to 区域中去,这其中还 可以顺便整理内存空间,使得获得一个 比较大的连续的内存空间
  3. 然后 在一轮的 GC 之中还存活着的话,那就把 新生代的 内存放到 老生代去
  4. 在这之后,to 空间 就变成了 from 空间,而原来的 from 空间就会被清空,成为 to 空间,也就是进行 调换

下面重点来简单介绍一下 各种内存 处理的算法

  执行过程 是否可以立即执行 缺点 优点
引用计数   引用 计数器,判断当前的引用数是否为0,当为0的话,就可以直接删除 是,只要计数器为 0,可以立即执行

1、无法回收循环引用的对象

2、  空间开销大

 
标记清除

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

        其实就是从代码层面 去 找一遍能找到的对象, global 开始查找

      找到了就进行标记

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

      然后 把所有没有被标记的 给 删除

1、容易导致 空间的碎片化,空间的不连续

 2、不能立即回收对象,回收的时候,程序停止工作

解决了 循环引用的问题
标记整理

当想把 新生代 往老生代的空间移动,但是不足以 完成晋升,就会对老生代执行

和 标记清除一样,但是会对空间进行整理,让空间能够出现连续

不能立即回收对象,回收的时候,程序停止工作,最长也就1s 这里的执行比较缓慢,毕竟是对 老生代这么大的东西进行整理,所以会导致 js 的性能问题
标记增量

1、对需要进行清除的 内存进行 一点一点地进行标记,但是并不立刻删除

2、然后 标记一点,就执行一段 js 代码,接着再 标记一点,又去执行一点代码(类比于 js 中的 requestIdeCallback)

3、等到标记完成了,对所有标记的 垃圾对象进行一次性删除

执行的时候会导致 js 停止执行 并不会导致 js 一次性停止太长的时间,提高用户体验
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章