浏览器的垃圾回收机制

在日常的开发过程中,我们不断的定义变量和函数,然后使用、调用,但是是否没有想到过,当代码执行过后,这些变量都去了哪里。其实是浏览器自己会对没有用的对象进行清除。那怎么算是没有用的了?

可达性

一个对象是否具有可达性决定了它时候还有用,或者说是有被用到。

可达性表示对象是否可以被访问到,如果不能被访问到,就会被浏览器的垃圾回收机制回收。

回收策略

回收策略就是浏览器如何找出这些不可达对象的策略或者说是一种算法,然后把它们清除。

常见的回收策略:

  • 引用计数算法
  • 标记清除算法
  • 标记整理算法

引用计数算法

引用计数算法很简单,如果对象没有被使用那么它的引用计数就为0,有被用到就增加1。一旦对象的引用计数为0之后,那么这个对象就会被清除

引用计数算法的优点就是很清晰,引用计数为0,那么对象就是没有被用到,就立即直接清除掉。

但是如果对象存在循环应用,那么他们的引用计数就不可能为0,所以对象就不会被清除,所以这也是该算法的缺点

标记清除算法

标记清除算法是大多数浏览器都在使用的垃圾回收算法,它将回收分为两个阶段:标记和清除阶段,标记阶段通过从根节点递归遍历,将能访问到的都加上一个标记,清除阶段就将没有标记的对象清除。

优点

  • 解决了引用计数的循环引用的问题,因为标记清除算法采用了递归遍历对象的方式

缺点

  • 内存碎片化

标记清除算法清除之后,内存就会存在不同大小的内存块,而在分配内存的时候可能因为对象过大而找不到合适的内存块。

标记整理算法

标记整理算法和标记清除算法在垃圾回收都是一样的,标记整理算法会在清除之后,将没有被清除的对象统一复制到内存的一端。就解决了标记清除算法的内存碎片化的缺点。

V8的垃圾回收机制

V8是一个Javascript引擎,相对于其他引擎做了很多的优化

3m7zv-knrhh.jpg

V8的垃圾回收机制采用的分代式垃圾回收,将堆内存分为新生代和老生代两个内存块

  • 新生代

新生代表示存活时间较短的对象,它能存储的对象很小只有1~8M

新生代又将它内部分为使用区和空闲区,新加入的对象会放在使用区,当使用区快被存慢的时候,就会进行垃圾回收,将使用区中的活动对象加上标记,然后将加上标记的对象复制到空闲区,然后将使用区清空,再将使用区和空闲区对调,空闲区变成使用区。

当空闲区占了25%,那么剩下的活动对象就会自动晋升到老生代。一个对象经历一次或多次回收之后依然存在新生代中,就会把该对象晋升到老生代。

  • 老生代

老生代则是采用的是标记整理算法,通过标记清除来回收垃圾,再将存活的对象复制到内存的一端。

增量标记

增量标记是V8对垃圾回收机制的优化,当在回收比较大的对象的时候,如果一下全部清除,会花费比较大的时间,V8就采用了增量标记的方式,将垃圾回收分成很多小步,让js代码执行一会儿,再清理一次,再让js执行一会儿,减少每次回收的时间。