GC算法介绍
GC定义与作用
-
GC就是垃圾回收机制的简写
-
GC可以找到内存中的垃圾、并释放和回收空间
GC里面的垃圾是什么
- 程序不再需要使用的对象
// 一
// 第一种角度就是看这个变量是否还会被引用
// 不再会被引用了就是垃圾
function func () {
name = 'lg'
return `${name} is a coder`
}
func()
// 二
// 第二种是看这个变量是否还能被引用到
// 引用不到了就是垃圾
function func () {
const name = 'lg'
return `${name} is a coder`
}
func
GC算法是什么
- GC是一种机制,垃圾回收器完成具体的工作
- 工作的内容就是查找垃圾、释放空间、回收空间
- 算法就是工作时查找和回收所遵循的规则
常见的GC算法
- 引用计数
可以通过一个数字来判断当前的一个对象是不是一个垃圾
- 标记清除
给活动对象添加一个标记俩判断它是否是一个垃圾
-
标记整理
-
分代回收
引用计数算法实现原理
核心思想就是在内部通过一个引用计数器来维护当前对象的引用数,从而判断该对象的引用数值是否为零,来决定它是不是一个垃圾对象,当这个数值为零的时候GC算法就开始工作,将其所在的一个对象空间进行回收和释放再使用。
- 核心思想:设置引用数,判断当前引用数是否为0
- 引用计数器
- 引用关系改变时修改引用数字
- 引用数值为0时立即回收
当某一个对象的引用关系发生改变的时候,引用计数器就会主动的去修改当前这个对象所对应的引用数。
引用关系发生改变?例如说我们的代码里面有一个对象空间,每有一个变量名指向它就把引用数值加1,每有一个变量名不再指向它就把引用数值减1,当变成0的时候,GC就会立即工作将这个对象空间进行回收和释放再使用。
const user1 = {name:11}
const user2 = {name:22}
const user3 = {name:33}
const nameList = [user1.name, user2.name, user3.name]
function fn() {
const num1 = 1
num2 = 2
}
fn()
window对象下面挂载的对象有user1\user2\user3\nameList\num2,对于这些变量来说,他们的引用计数至少是1。
当fn函数执行完毕num1这个变量的引用数值就会变成0,然后GC就会立即开始工作,进行垃圾回收。
简单来说就是依据当前对象上面的引用数值来判断是否是垃圾对象。
引用计数算法的优缺点
优点
- 发现垃圾时立即回收(一旦引用数值为0)
- 最大限度减少程序的暂停
缺点
- 无法回收循环引用的对象
- 时间开销大(一直监听着对象的引用数值的变化)
function fn() {
const obj1 = {}
const obj2 = {}
obj1.name = obj2
obj2.name = obj1
return 'hello'
}
fn()
上述代码中obj1和obj2两个对象存在循环引用的关系,当fn执行完毕,GC还是会检测到这两个对象都还存在着被引用的地方,即他俩的引用数值都还是1,所以就不会当作垃圾被回收,即使全局已经不能再获取到这两个对象,他还是不会被回收,这就造成了内存的浪费。
标记清除算法实现原理
标记清除算法将整个垃圾回收操作分成两个阶段,第一个阶段会去遍历所有的对象找到活动对象(可达对象)进行标记的操作;第二个阶段也会去遍历所有的对象把没有被标记的对象进行清除,并将第一阶段的标记清除。
通过两个遍历对垃圾空间进行回收,并将相应的内存空间交给一个空闲列表进行维护,以便后续的代码可以直接使用这些被释放的空间。
- 核心思想:分标记和清除两个阶段完成
- 遍历所有对象找标记活动对象
- 遍历所有对象清除没有标记对象
- 回收相应空间
通过递归的方式遍历每一个节点,将可达对象进行标记,然后将无标记对象进行清除同时将有标记对象的标记抹除。还会将释放的空间交给空闲列表供后续直接使用。
标记清除算法优缺点
优点
- 可以解决对象循环引用的回收问题
在一个函数中定义了a1和b1,让他们互相引用,当这个函数调用结束之后必须将其内部的空间进行释放,因为当调用完毕之后,它局部空间中的变量就会失去与当前全局global在作用域上的连接,不能被访问了,这个a1和b1就是不可达对象,不可达对象就不会被标记,然后再第二次遍历中就会被释放。但是在引用计数算法中是会漏掉这种空间的回收。
缺点
- 内存空间碎片化
标记清除算法的垃圾空间被回收到空闲列表中之后,会以内存碎片的形式存在,也就是说这些空闲的内存空间的内存地址是不连续的。这就是内存空间的碎片化。这种现象出现的原因就是回收的垃圾对象的空间在地址上本身就是不连续的,由于这种不连续就造成了再回收之后存在于各个角落。
-
不会立即回收垃圾对象
-
清除的时候当前的程序时停止工作的
问题:引用计数算法不会出现空间碎片化吗?
标记整理算法实现原理
- 标记整理算法可以看作是标记清除算法的增强
- 标记阶段的操作和标记清除算法完全一致
- 清除阶段会先执行整理,移动对象位置,让地址连续再回收