垃圾回收
标记清除算法
目前JavaScript引擎中最常用的算法,不同浏览器厂商有对此进行加工,所以存在差异。
像算法名字一样,这个算法分为标记和清除阶段
- 标记阶段:为所有活动对象做上标记
- 清除阶段:把没有标记的对象销毁
引擎在执行GC时,需要从出发点去遍历内存中所有对象并打上标记。而这个出发点有很多,称其为一组根对象,如全局window 对象,文档DOM树等。
- 标记清除算法大致过程
- 1.辣鸡收集器在运行时给内存中所有变量加上一个标记,假设内存中所有对象都是辣鸡,全部标记为0
- 2.然后从各个跟对象开始遍历,把不是辣鸡的节点改成1
- 3.清理所有标记为0的垃圾,销毁并回收它们占用的内存空间
- 4.最后把所有内存中对象标记修改为0,等待下一轮垃圾回收
- 优点
- 优点只有一个,实现比较简单,打标记无非打与不打两种情况
- 缺点
- 垃圾清除之后,剩余的对象内存位置时不变的,也会导致闲置内存空间不连续,出现了内存碎片,并且由于剩下的内存空间不是 一整块。
垃圾清理之后,剩余的空间可能时多个小块,而不是一整块,因此产生可内存分配的问题。例如需要为size大小的数据分配内存...
- 内存分配
- firs-fit:找到大于等于size的块立即返回
- best-fit:遍历整个空闲列表,返回大于等于size的最小分块
- worst-fit:遍历整个空闲列表,找到最大的块,然后切成两部分,一部分size大小,并将该部分返回。
因此标记清除算法有两个明显的缺点
1.内存碎片化:空闲内存块时不连续的,可能造成分配内存过大时找不到合适的块
2.分配速度慢,即便使用first-fit策略,仍然时一个O(n)操作
- 标记清除算法补充
归根结底,标记清除算法的缺点在于清除之后剩余的对象位置不变而导致空闲的内存不连续,所以只要解决这一点,两个缺点就都能解决。
而标记整理(Mark-Compact)算法可以有效解决,在标记结束后,标记整理算法会将活动对象向内存的一段移动, 最后清理掉边界的内存。
引用计数法(很少用了)
引用计数法把对象是否不再需要简化定义为:对象有没有其他对象引用到它,如果没有引用指向该对象,对象将被垃圾回收机制回收。
- 策略
- 声明一个变量并且将一个引用类型复制给改变量的时候,这个值的引用次数为1
- 如果同一个值得又被赋值给另一个变量,那么引用次数加1
- 如果改变量得值被其他得值覆盖,则引用次数减1
- 当这个值得引用次数变为0,说明没有变量在使用,这个值没法被访问,回收空间、垃圾回收器会在运行得时候清理 掉引用次数为0得值占用得内存