theme: channing-cyan
这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战
一、标记-清除
标记-清除(Mark-Sweep) 完整流程如下:
- 【标记】使用可达性分析算法判断要回收的对象,并进行标记
- 【清除】清除标记的回收的对象
如图上所示,标记-清除的缺点很明显,第一是清除掉标记的对象后,极易产生内存碎片。假如我们要给一个超大的字符串数组分配一个空间, 因为数组的内存空间是连续的,所以JVM可能找不到合适的内存去存储它,然后就会触发一下次垃圾回收。
第二就是执行效率很不可控,假如堆中大部分的对象都是可回收的,收集器要执行大量的标记、手收集操作。
二、标记-整理
标记-整理/压缩(Mark-Compact) 完整流程如下:
- 【标记】与标记-清除的第一步不能说一模一样,只能说完全相同
- 【整理】把所有的存活对象压缩到内存的一端
- 【清除】清除掉边界之外所有的空间
相较之于标记-清除,因为做了一次整理操作,所以垃圾对象清除后,解决内存碎片的问题,同时也不存在空间浪费的问题。是不是完美,你想多了!整理这步操作,本身会消耗资源,甚至如果内存中存活的对象很多,并且都是一些占内存空间较小的对象,并且要回收的垃圾对象很少时,垃圾收集器要移动大量的存活对象才能换取少量的内存空间,实在是不划算,这个便是标记-整理的缺点。
三、标记-复制
标记-复制(copy) 完整流程如下:
- 【内存均分】把内存分为两块区域(运行区域、保留区域),每次只是使用运行区域
- 【标记】标记流程跟前面两种算法相同
- 【复制】将正在运行区域中使用的存活对象复制到保留区域
- 【清除】清除掉运行区域中的所有对象
- 【交换空间】交换两个内存块的角色,等待下一次回收
标记-复制算法整个流程很像“踢皮球”,存活的对象在运行区域和保留区域被踢来踢去。这种算法的优点很明显,在大量垃圾对象的情况下,只需要复制少量的存活对象,而且并不会产生内存碎片,很好的兼顾了效率和内存碎片的问题。那是不是又完美了?并不是,每次都要预留一半的区域,很浪费,这个是典型的以空间换时间的算法。而且如果内存中存活对象多,要回收的对象少,收集器也是要复制操作多次 才能释放少量的空间,很不划算。
四、总结
三种算法的区别 算法名 | 主要优点 | 主要缺点 | | ----- | ------- | --------------------- | | 标记-清除 | 实现简单 | 清除后可能会存在内存碎片,影响分配内存效率 | | 标记-整理 | 无碎片 | 整理存在开销 | | 标记-复制 | 性能好、无碎片 | 内存利用率低 |