乐趣区

关于java:垃圾回收算法

对于垃圾回收算法,大抵可分为标记 - 革除算法、标记 - 复制算法、标记 - 整顿算法。简直所有垃圾收集器都或多或少蕴含着这些算法思维。在解说这三种算法之前,必须得说说分代收集实践 – 大抵就是将一些朝生夕灭的对象划分在一个区域(新生代),将一些存活工夫较长的对象换分在另一个区域(老年代),而后不同的区域采纳更适宜其特点的垃圾回收算法和垃圾收集器。从而达到缩短垃圾收集工夫,进步吞吐量等目标。

  • 标记 - 革除算法

这算是一种最根本的垃圾回收算法了,思维也很简略,就是先对对象做标记(至于如何标记,能够看下后面可达性剖析算法这篇文章),而后间接将标记为垃圾的对象清理掉。

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

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

  • 标记 - 复制算法

标记 - 复制算法的根本思维是把堆空间划分为大小相等的两份,每次只采纳其中一份来进行对象调配,在应用的这份内存空间快满了的时候,就把这一份内存空间中的存活对象复制到另一份内存空间上,而后把这一份内存空间一次清理掉。这种算法能够无效地防止内存碎片问题,但同时也会节约一半的内存空间。

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

  • 标记 - 整顿算法

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

退出移动版