参考 《深入理解Java虚拟机 JVM高级特性与最佳实践》 3.3节
1.标记-清除算法
主要不足有两个:
- 效率问题:标记和清除两个过程的效率都不是很高
- 空间问题:标记清除后会产生大量内存碎片,会导致之后有较大对象需要分配时找不到足够大的连续内存而又出发垃圾回收动作。
2.复制算法
- 复制算法将内存分成了大小相等的两块,每次只使用其中的一块。当这块内存用完了,触发垃圾回收,就将这块内存中还活着的对象复制到另一半内存上,这个时候是不用整理的,直接一个一个推进去即可,这样就不用考虑内存碎片的问题了。这种算法的代价是将内存缩小了一半,代价太大了。
- 商业虚拟机的做法是把内存分为一块较大的Eden(伊甸园,大概就是指没有"杀戮"的乐园的意思吧)空间,和两块较小的Survivor(就是存活下来的那些对象)空间(8:1:1)。使用的时候启用Eden空间和一块Survivor1空间,回收的时候把这两块空间还存活的对象(Survivor)复制到剩余的那块Survivor2空间上去,接着清空刚刚使用的Eden空间和Survivor1空间,然后下一轮使用Eden空间和Survivor2空间,Survivor1作为收集存活对象的区域,往复循环。
- 为什么上图中的复制算法只使用了两块内存,而商业虚拟机使用了三块内存呢?刚开始还觉得很奇怪,觉得奇怪但是又找不出来到底哪里不对。是这样的,如果是像上图中那样两块内存的话,当第一轮回收后,存活的对象都在Survivor区域后,下一轮,这个Survivor区域就要当做Eden来使用了,如果按8:2的比例来分配的话,那此时可使用的内存就剩总内存的20%了,这不现实,所以采用了三块内存的方式,Survivor1和Survivor2轮流作为Eden的一部分来使用。
- 因为不能保证每次存活下来的对象都在10%以下,如果出现多余10%的对象存活下来了,那就需要依赖其他内存(这里指老年代)进行分配担保。多余10%的那部分对象会通过分配担保机制进入老年代。
3.标记-整理算法
-
标记整理算法跟标记删除算法大致上差不多,就是比标记删除算法多了个整理的过程,即在清理前把或者的对象整理到一起,这样清理起来效率会高一点。
4.分代收集算法
- 分代算法也没有什么新的思想,就是对堆中的对象进行分代,然后对老年代使用标记-整理算法,对新生代使用复制算法。
- 老年代存活率较高,新生代存活率较低。
5.暂时我自己的理解
- 一个对象只要逃过它面临的第一次垃圾收集后,它就成为老年代的成员了
- 被回收的都是大量的临时对象吧