垃圾回收算法

对于垃圾回收算法,大致可分为标记-清除算法、标记-复制算法、标记-整理算法。几乎所有垃圾收集器都或多或少包含着这些算法思想。在讲解这三种算法之前,必须得说说分代收集理论--大致就是将一些朝生夕灭的对象划分在一个区域(新生代),将一些存活时间较长的对象换分在另一个区域(老年代),然后不同的区域采用更适合其特点的垃圾回收算法和垃圾收集器。从而达到缩短垃圾收集时间,提高吞吐量等目的。

  • 标记-清除算法

这算是一种最基本的垃圾回收算法了,思想也很简单,就是先对对象做标记(至于如何标记,可以看下前面可达性分析算法这篇文章),然后直接将标记为垃圾的对象清理掉。

这种算法有一个很大的缺点,就是容易产生内存碎片,内存碎片过多,会导致大对象在分配内存时因没有足够的内存空间(其实各个碎片化的内存加起来是有很大的空间的)而导致提前触发一次Full GC 。虽说可以通过一些特定的手段来在碎片空间内分配对象,但是同时会带来其他一些影响。

这种算法的优点呢,就是可以相对而言比较容易地实现并发收集(垃圾收集线程与用户线程并发),例如CMS垃圾收集器就是采取的这种算法进行老年代的垃圾回收。但是其内存碎片问题还是有很大的影响,所以CMS收集器采取了一个折中方案,在内存碎片过多的时候采取标记-整理算法。

  • 标记-复制算法

标记-复制算法的基本思想是把堆空间划分为大小相等的两份,每次只采用其中一份来进行对象分配,在使用的这份内存空间快满了的时候,就把这一份内存空间中的存活对象复制到另一份内存空间上,然后把这一份内存空间一次清理掉。这种算法可以有效地避免内存碎片问题,但同时也会浪费一半的内存空间。

所以,对于以分代收集理论为基础的一些垃圾收集器来说,其新生代的对象大多是朝生夕灭的,每次存活的对象仅占少数,这就比较适合采取这种算法来进行垃圾回收。不过为了节省内存,新生代的布局默认是分为一个Eden区和两个Survivor区,比例8:1:1,当然这个比例是可以通过启动参数进行调剂的。每次使用分配对象的内存为Eden和其中一个Survivor,垃圾收集时,就把存活对象复制到另一块Survivor中,这样相当于只浪费了10%的内存空间。总之,标记-复制算法很适合新生代对象的特点,大多数经典垃圾收集器新生代收集算法就是采用的标记-复制算法。

  • 标记-整理算法

标记-整理算法的基本思想是将存活的对象向内存空间移动,然后一次清理掉移动后边界之外的内存空间。其优点是没有内存碎片,但是若要实现并发整理(垃圾收集线程与用户线程并发,且无内存碎片),有一定的难度,目前只有一些新一代的低延迟垃圾收集器实现了并发整理,如Shenandoah、ZGC等垃圾收集器。像G1,CMS垃圾收集器(内存碎片过多时)的整理阶段都是采用Stop The World方式,会完全暂停用户线程

你可能感兴趣的:(java后端jvmjvm调优)