什么情况JS会自动垃圾回收
- 没有被引用的对象会被垃圾回收
- 对象只是相互引用会被垃圾回收
垃圾回收在前端中的特殊性
由于前端中存在js进程和浏览器进程。因此导致了一些特殊性。但是垃圾的回收时机依然离不开前面两句话。
对象被浏览器引用
创建一个div并插入到页面中,监听点击事件。最后将div设置为null。首先我们知道浏览器上的div是依然存在的。但是会有一个问题div不是被设置为null了嘛,那么点击页面上的div还会打印吗。
let div = document.createElement('div')
div.innerText = 'hi'
document.body.appendChild(div)
div.onclick = function() {
console.log(this)
}
div = null
虽然js进程取消了对div的引用,但是浏览器进程却引用了div所指向的DOM对象。事件依然是有效的,说明div并没有被垃圾回收。因为浏览器还对div存在引用关系。
对象被js引用
反之只是移除了在浏览器中的DOM对象,而js依然引用着,也是不会被垃圾回收。我们仍然可以随时将div添加到页面中。
let div = document.querySelector('div')
div.remove()
真正的被回收
只有将浏览器中的DOM元素删除,在js中解除对div的引用,才会被垃圾回收
const div = document.createElement('div')
div.innerText = 'hi'
document.body.appendChild(div)
+ div.remove() //删除浏览器中div
div = null //解除对div DOM元素的引用
如此依赖div彻底失去了浏览器和js的引用,它将会面临被垃圾回收
垃圾回收算法
标记清除(mark swipe)
思路
标记:从根集合出发,将所有活动对象及其子对象打上标记
清除阶段:遍历堆,将非活动对象(未打上标记)的连接到空闲链表上
空闲链表中的就是需要清除的对象
优点
实现简单,容易和其他算法配合使用
缺点
对象过多需要标记的对象也随之增加。
引用计数算法
使用一个map对每个对象的引用次数进行累计。对象被引用一次就进行加一操作,当对象被解除引用就进行减一操作,当对象的引用数量为0的时候就将该对象当作垃圾回收。
优点
不需要再查找需要清除的对象上耗费时间
缺点
无法回收相互引用的对象。
需要额外的存储空间保存对象引用数量的map
优化算法
分代回收
将对象分为新生代和老生代。例如出现的早的对象分为老生代比如window对象,晚出现的分为新生代如函数作用域中创建的对象。减少对老生代的检测频率,提高对新生代的检测频率。
该算法是根据新出现的对象完成它的工作很快就会死亡。
增量回收
分批次进行检查是否需要垃圾回收。比如需要对一万个对象进行检查,每次只检查一千个,从而空出线程有机会给其他任务执行。
该算法思路就是将所有需要检测的回收的对象,分为一小部分一小部分进行检查。
空闲回收
js线程总不会一种都在忙。垃圾回收只在CPU空闲的时候进行,执行减少对其他程序执行的影响。
总结
拓展阅读:V8之旅