目录
- GC相关概念
- 常见GC算法
引用计数算法
- 核心思想
- 实现原理
- 实例
- 优缺点
标记清除算法
- 核心思想
- 实现原理
- 图示
- 优缺点
标记整理算法
- 核心思想
- 实现原理
- 图示
- 优缺点
GC相关概念
- [x] GC:垃圾回收机制的简写,垃圾回收期完成具体的工作.可以找到内存中的垃圾、并释放和回收空间
- [x] GC垃圾:程序中 不再需要使用的,程序中不能再访问的 对象
- [x] GC算法:是GC工作时查找和回收所遵循的规则
常见GC算法
- 引用计数
- 标记清除
- 标记整理
- 分待回收(V8用到的)
引用计数算法
核心思想
设置引用数,判断当前引用数是否为0
来决定是不是垃圾对象,如果是0
就GC
就进行工作,进行回收。
实现原理
- 引用计数器
- 引用关系改变时修改引用数字
- 引用数字为
0
时立即回收
实例
const user1 = { age: 11 }
const user2 = { age: 12 }
const user3 = { age: 13 }
const nameList = [user1.age, user2.age, user3.age]
function fn() {
const num1 = 1
const num2 = 2
num3 = 3
}
fn()
当函数调用过后,num1
和num2
在外部不能使用,引用数为0
,会被回收 ;num3
是挂载在window
上的,所以不会被回收 ;
上面的user1
、user2
、user3
被nameList
引用,所以引用数不为0
不会被回收 ;
优缺点
引用计数算法 | 内容 |
---|---|
优点 | 1. 发现垃圾时立即回收<br/>2. 最大限度减少程序暂停,让空间不会有被占满的时候 |
缺点 | 1. 无法回收循环引用的对象<br/>2. 资源消耗开销大(对所有对象进行数值的监控和修改,本身就会占用时间和资源) |
下面举一栗子说明上面缺点中无法回收循环应用对象的情况:
function fn() {
const obj1 = {}
const obj2 = {}
obj1.name = obj2
obj2.name = obj1
return 'hello world'
}
fn()
// obj1和obj2,因为互相有引用,所以计数器并不为0,fn调用之后依旧无法回收这两个对象
标记清除算法
相比原理实现更加简单,还能解决相应问题,V8
当中会大量使用到。
核心思想
分 标记
和 清除
两个阶段完成
实现原理
- 第一阶段:遍历所有对象找活动对象(可达对象)
标记
(层次用递归进行操作) - 第二阶段:遍历多有对象
清除
没有标记对象并抹掉第一个阶段标的标记 - 回收相应空间,将回收的空间加到
空闲链表
中,方便后面的程序申请空间使用
图示
优缺点
标记清除算法 | 内容 |
---|---|
优点 | 相对于引用计数算法来说解决对象循环引用的问题,局部作用域里面的内容无法被标记,所以即使有引用还是会被清除掉 |
缺点 | 1. 空间链表地址不连续(空间碎片化),不能进行空间最大化使用<br/>2. 不会立即回收垃圾对象,清除的时候程序是停止工作的。 |
下面是空间链表地址不连续的图示,可以更好的帮我们理解:
左边释放了2
个字的空间,后边释放了1
个字的空间,虽然看起来是释放了3
个字的空间,但是地址是不连续的。如果要申请一个1.5
字的空间,使用左边空间浪费了0.5
,时候右边又不够,会造成无法最大化使用。
标记整理算法
这个算法和标记清除算法配合在V8
中也是广泛应用。
核心思想
在 标记 和 清除 中间,添加了内存空间的 整理
实现原理
- 标记整理可以看做是标记清除的 增强
- 标记阶段:与标记清除一致
- 整理阶段:清除钱先执行整理,移动对象位置,在地址上产生连续
- 清除阶段:与标记清除一致
图示
开始会有很多活动对象和非活动对象,还有一些空闲空间,回收前先开始整理
整理之后要将非活动对象进行清除
最后就留出了整个的空闲空间
优缺点
标记整理算法 | 内容 |
---|---|
优点 | 相较标记清除算法减少了碎片化空间 |
缺点 | 不会立即回收垃圾对象,清除的时候程序是停止工作的。 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。