常见的垃圾回收算法:
- 引用计数:每个对象维护一个引用计数,当被引用对象被创建或被赋值给其他对象时引用计数自动加 +1;如果这个对象被销毁,则计数 -1 ,当计数为 0 时,回收该对象。
- 优点:对象可以很快被回收,不会出现内存耗尽或到达阀值才回收。
- 缺点:不能很好的处理循环引用
- 标记-清除:从根变量开始遍历所有引用的对象,引用的对象标记“被引用”,没有被标记的则进行回收。
- 优点:解决了引用计数的缺点。
- 缺点:需要 STW(stop the world),暂时停止程序运行。
- 分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,短的放入新生代,不同代有不同的回收算法和回收频率。
标记清除算法缺点:
- 碎片化严重(由上面描述的分配算法可知,容易产生大量小的分块
- 分配速度慢(由于空闲区块是用链表实现,分块可能都不连续,每次分配都需要遍历空闲链表,极端情况是需要遍历整个链表的。
- 与写时复制copy on write不兼容:
写时复制(copy-on-write)是众多 UNIX 操作系统用到的内存优化的方法。比如在 Linux 系统中使用 fork() 函数复制进程时,大部分内存空间都不会被复制,只是复制进程,只有在内存中内容被改变时才会复制内存数据。
但是如果使用标记清除算法,这时内存会被设置标志位
,等同于改动了数据。这时候 “ 写时复制技术 ” 会判断对象已经被改动,从空闲内存中写入新的对象并改写原指针。因此会频繁发生不应该发生的复制。
解决方案:使用位图(bitmap)标记法,就可以兼容了!
延迟清除法(Lazy Sweep)是缩减因清除操作而导致的最大暂停时间的方法。在传统的标记清除算法中,标记和清除是依次进行的,即先标记所有的活动对象,然后再清除未标记的对象。而延迟清除法则将清除阶段延迟到下一次的标记阶段之后进行,以减少清除操作对应用程序的影响。