[Understanding Java Garbage Collection]理解Java垃圾收集(二)

来源:互联网 发布:美萍软件介绍 编辑:程序博客网 时间:2024/05/16 09:21

原文链接:http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/

GC老年代

老年代GC基本上是在空间慢的时候发生。执行过程与GC的类型有关,因此在你了解GC的种类之后更简单。

根据JDK7,有5中GC类型。

  1. Serial GC
  2. Parallel GC
  3. Parallel Old GC (Parallel Compacting GC)
  4. Concurrnt Mark & Sweep GC (or “CMS”)
  5. Garbage First(G1) GC

以上里面,serial GC一定不能用在服务器上。GC的类型在桌面计算机还只有一个CPU核的时候被创建。使用serial GC会极大的
减少性能。

下面我们来了解一下每种GC的类型。

Serial GC (-XX:+UseSerialGC)

新生代GC使用这种类型,我们在前面说过。老年代GC使用一种叫做“mark-sweep-compact”的算法。

  1. 算法的第一步是标记老年代中存活的对象。
  2. 然后,它从头开始检查堆,只留下存活的对象(清除)。
  3. 最后一步,它从头开始填满堆,并把堆分为两部分:一部分有对象,一部分没有对象(压缩)。

serial GC适合内存比较少和CPU核比较少的情况。

Parallel GC (-XX:+UseParallelGC)

difference-between-the-serial-gc-and-parallel-gc.png
图4 Serial GC与Parallel GC的区别

从图上,你可以轻易地看到Serial GC与Parallel GC的区别。serial GC只使用一条线程去执行GC,Parallel GC使用多条线程去处理GC,因此,它更快一点。这种GC在内存足够和CPU核很多的时候,会比较有用。因此叫做“throughput GC”。

Parallel Old GC(-XX:+UseParallelOldGC)

Parallel Old GC从JDK5更新的时候就开始得到支持。与Parallel GC相比,唯一的区别就是使用的老年代GC算法不一样。它有几步:标记-汇总-压缩。汇总这步与标记-清除-压缩算法中的清除步骤不一样的是,它将对象分配到GC预先处理!好的地方。这一步有一点复杂。

CMS GC (-XX:+UseConcMarkSweepGC)

serial-gc-and-cms-gc.png
图5 Serial GC与CMS GC

你可以从上图看到,并发标记-清除GC比前面提到的其他GC更复杂一点。最初的初始标记比较简单。离类加载器最近的存活对象被搜索到。因此暂停时间比较短。在并发标记步骤,存活对象被刚刚跟踪和确认的对象所引用。这一步的不同是它与其他线程在同一时间执行。在重标记步骤,在并发标记步骤新添加的对象或者停止的对象被检查。最后,在并发清除步骤,交给垃圾收集器处理。垃圾收集器在其他线程执行的时候启动。因为这种GC以这种方式执行,所以暂停时间非常短。CMS GC也叫做低时延GC,用在响应时间很严格的程序中

这种GC有短的stop-the-world的时间的优点,也有下面的优点:

  • 与其他GC类型相比,消耗更多的内存和CPU
  • 默认是不支持压缩步骤的

你在使用这种GC前要仔细考虑。如果因为内存碎片过多,需要启动压缩任务时,stop-the-world时间就会比其他GC要长。你需要检查多频繁和多久执行一次压缩步骤。

G1 GC

最后,我们来学习一下garbage first(G1)GC。

layout-of-g1-gc.png
图6 G1 GC的布局

如果你想了解G1 GC,忘记你所知道的所有关于新生代和老年代的东西。你可以从图中看出,一个对象被分配到一个格子中,然后GC被执行。然后,一旦一个区域满了,对象就会被分配到其他区域,然后GC就会执行。这里找不到数据从新生代移动到老年代的步骤。这种GC用来替代有很多问题并饱受争议的CMS GC。

G1 GC最大的优点是性能。它比我们前面讲的其他任何类型的GC都要快。但是在JDK6中,这叫做early access,并且只是用来测试。在JDK7中被正式加进来。我个人看来,在NHN能在实际服务中使用JDK7还需要很长时间(至少一年)。因此你必须等一等。另外,我经常听说JDK6在应用G1 GC之后,经常崩溃。在稳定之前请等一等。

我会在下面介绍GC优化,但是之前我要告诉你一件事。如果所有创建的对象的大小和类型在程序中是明确的,我们公司中使用的WAS的所有GC选项都会是一样的。但是WAS创建的所有对象的大小和类型都是依服务而定的,而且设备类型也千差万别。换句话说,仅仅因为特定的服务使用GC选项“A”,并不意味着不同的服务使用相同的选项就能获得最好的结构。有必要通过持续监控和优化找到WAS线程,每个设备的WAS实例和GC选项最合适的参数。这不是我个人的经验,这来自为JavaOne 2010创建Oracle JVM的工程师的讨论。

这个问题中,我们仅仅看了一下Java中的GC。我们在后面会了解更多关于怎么监控Java GC状态和优化GC。

我需要提醒一下,我参考了一本2011年11月出版的叫做“Java 性能”的书(亚马逊,可以通过Safari在线查到,如果有账号的话),和一本“Java HotSpot虚拟机内存管理”的Oracle官网提供的白皮书。

作者,Sangmin Lee,性能工程实验室高级工程师,NHN公司。

0 0