一、常见的几种垃圾收集算法
1.1标记-清除算法
最基础的收集算法是标记-收集(Mark-Sweep)算法,该算法分为标记和清除两个阶段:首先标记处所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
- 优点:容易实现
- 缺点:清除后会产生大量不连续的内存碎片,可能会导致之后分配较大内存时找不到足够空间,不得不提前触发另一次垃圾集
1.2复制算法
复制(Copying)算法将可用的内存分为大小相等的两块,每次只使用其中一块,当这一块用完时,就将任然存活的对象复制到另一块上,然后对已使用过的内存空间进行一次性完全清理
- 优点:内存分配时不需考虑内存碎片的问题,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效
- 缺点:将内存缩小为了原来的一半
1.2.1分配担保
因为新生代中的绝大多数对象的存活时间都很短,所以不需要将内存进行1:1划分,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,大小比例为8:1:1。
每次使用Eden和一块Survice空间,当回收时,将Eden和Servivor中存活的对象一次性的复制到另一块Servivor空间中。这样就只有10%的内存被“浪费”。当然,我们无法保证每次都只有10%以下的对象存活,当Servivor空间不足时,需要依赖老年代进行分配担保(Handle Promotion)。即当另一块Servivor不足以存放回收后仍存活的对象时,这些队形将直接通过分配担保进入老年代。
- 优点:减少了内存空间的浪费
- 缺点:当需要复制大量对象时效率会下降,需要额外的空间做担保
1.3标记-整理算法
标记-整理(Mark-Compact)算法,该算法与标记-清除算法的过程相同,但后续步骤不是对对象的直接清除,而是让所有存活的对象向内存的一端移动,然后清理掉边界外的内存。
- 应用:主要应用于老年代
1.4分代收集算法
当前商业虚拟机的垃圾收集都采用分代收集(Generation Collection)算法,这种算法并没有什么新思想,只是根据对象存活的时间将内存分为几块。一般是将java堆分为新生代和老年代,这样可以根据不同年代的特点使用合适的收集算法。
一般来说:
- 新生代:复制算法
- 老年代:标记-清理算法或者标记-整理算法