Java 垃圾收集入门

 

JVM 的类型繁多,最主流的垃圾回收器有 4 个分别是:

  • Serial 收集器(常用于单 CPU)
  • Throughtput (或者叫 Parallel)收集器
  • Concurrent 收集器(或者叫 CMS)
  • G1 收集器

概述

简单说,垃圾收集由两部组成:1,查找不再使用的对象;2,释放这些对象所管理的内存。

分代垃圾收集器

虽然实现细节千差万别,但是所有的垃圾收集器都遵循了同一个方式,即根据情况将堆划分成不同的代(Generation)。这些代被命名为老年代(Old Generation/ Tenured Generation)、新生代(Young Generation)。新生代又被进一步地划分为不同的区段,分别称为 Eden 空间和 Survivor 空间。

新生代是堆的一部分,对象首先在新生代中分配。新生代填满时,垃圾收集器会暂停所有的应用线程,回收新生代空间。不再使用的对象会被回收,仍然在使用的对象会被移动到其他地方。这种操作被称作 Minor GC

所有的垃圾收集算法在堆新生代进行垃圾回收时都存在“时空停顿”现象。

对象不断地被移动到老年代,最终老年代也会被填满,JVM 需要找出老年代中不再使用的对象,并对他们进行回收。而这通常是垃圾收集算法差异最大的地方。简单的垃圾收集算法直接停掉所有的应用线程,找出不再使用的对象,对其进行回收,接着对堆空间进行整理。这个过程被称为 Full GC,通常导致应用线程长时间的停顿。

另一方面,通过更复杂的计算,我们还有可能在应用线程运行的同时找出不再使用的对象;CMS 和 G1 收集器就是通过这种方式进行垃圾收集的。由于他们不需要停止应用线程就能找出不再使用的对象,CMS 和 G1 收集器被称为 Concurrent 垃圾收集器。同时,由于他们将停止应用程序的可能降到了最小,也被称为低停顿(Low-pause)收集器(也有叫无停顿收集器的)。Concurrent 收集器也使用各种不同的方法对老年代空间进行压缩。

使用 CMS 或者 G1 收集器,应用程序经历的停顿会更少(也更短)。其代价是应用程序会消耗更多的 CPU。CMS 和 G1 收集也可能遭遇产时间的 Full GC 停顿(尽量避免是这些调优算法要考虑的重要方面)。

GC 算法

1. Serial 垃圾收集器

Serial 垃圾收集是最简单的一种。如果应用运行在 Client 型虚拟机 (Windows 32 位或者单 CPU )上,这是默认的垃圾收集器。

2. Throughput 垃圾收集器

Throughput 收集器是 Server 虚拟机(多 cpu 的 unix 以及任何 64 位虚拟机)的默认收集器。

基本上不需要显式地弃用它,如果需要,可以使用 -XX:+UseParallelGC 或者 -XX:+UseParallelOldGC 来启用。

3. CMS 垃圾收集器

CMS 收集器的初衷是消除 Throughput 收集器和 Serial 收集器 Full GC 周期中的长时间停顿。CMS 收集器在 Minor GC 时会暂停所有的应用线程,并以多线程的方式进行垃圾回收。并改用新的算法来收集新生代(使用 -XX:+UseParNewGC)。

CMS 收集器在 Full GC 时不再暂停应用线程,而是使用若干个后台线程定期地对了年代空间进行扫描,及时回收器中不再使用的对象。这种算法帮助 CMS 称为一个低延迟的收集器。但是额外付出的代价是更高的 CPU 使用:必须有足够的 CPU 资源用于运行后台的垃圾收集线程。此外,后台线程不再进行任何的雅座整理工作,这意味着堆回逐渐变得碎片化。最终 CMS 会蜕化到 Serial 收集器:暂停所有应用线程,使用单线程回收、整理老年代空间。

通过使用 -XX:+UseConcMarkSweepGC-XX:+UseParNewGC 启用 CMS 垃圾收集器。(默认这两个标志是禁用的)

4. G1 垃圾收集器

G1 来集收集器(垃圾优先收集器)的设计初衷是为了尽量缩短处理超大堆(大于 4GB)时产生的停顿。G1 算法将堆划分为若干个区域(Region),不过他依旧数据分代收集器。这些区域中的一部分包含新生代,新生代的垃圾收集仍然采用暂停所有应用线程的方式,将存活对象移动到老年代或者 Survivor 空间。

G1 收集器属于 Concurrent 收集器:老年代的垃圾收集工作由后台线程完成,大多数的工作不需要暂停应用线程。

通过 -XX:+UseG1Gc 可以启动 G1 垃圾收集器。

就酱。

EOF


Power by TeXt.