Concurrent Mark Sweep Collector(CMS垃圾收集器官网规范翻译)

简介: CMS垃圾收集器旨在减少应用程序在垃圾收集过程中的暂停时间,通过利用多处理器的优势,在并发标记和并发清除阶段允许应用程序继续运行。这对于响应时间敏感的应用程序尤其有用,因为它可以显著降低GC暂停带来的影响。

​Concurrent Mark Sweep (CMS) Collector 收集器

The Concurrent Mark Sweep (CMS) collector is designed for applications that prefer shorter garbage collection pauses and that can afford to share processor resources with the garbage collector while the application is running. Typically applications that have a relatively large set of long-lived data (a large tenured generation) and run on machines with two or more processors tend to benefit from the use of this collector. However, this collector should be considered for any application with a low pause time requirement. The CMS collector is enabled with the command-line option -XX:+UseConcMarkSweepGC.

解释:

CMS收集器是被设计为 应用程序更短的垃圾收集停顿时间 并且可以 与应用程序运行的同时共享处理器资源,一般运行在两个或多个处理器的机器上,这个收集器认为应用程序有更短停顿时间的要求。

Similar to the other available collectors, the CMS collector is generational; thus both minor and major collections occur. The CMS collector attempts to reduce pause times due to major collections by using separate garbage collector threads to trace the reachable objects concurrently with the execution of the application threads. During each major collection cycle, the CMS collector pauses all the application threads for a brief period at the beginning of the collection and again toward the middle of the collection. The second pause tends to be the longer of the two pauses. Multiple threads are used to do the collection work during both pauses. The remainder of the collection (including most of the tracing of live objects and sweeping of unreachable objects is done with one or more garbage collector threads that run concurrently with the application. Minor collections can interleave with an ongoing major cycle, and are done in a manner similar to the parallel collector (in particular, the application threads are stopped during minor collections).

Young GC 包含了Eden GC S区GC 也是Minor GC

Old GC : Major GC ,Major GC 通常伴随Minor GC ,也就意味着会触发Full GC

Young GC + Old GC = Full GC

尽量减少GC频率 尽量减少Full GC频率 允许一定的Young GC

S0 S1 一定会有一块是空的,每回收一次 对象的分代年龄会加1

类似于其他收集器,cms收集器也是分代的,minor gc 和 major gc同时发生的,CMS收集器尝试通过使用独立的垃圾收集器线程,在应用程序线程执行的同时跟踪可到达的对象,从而减少由于major收集而导致的暂停时间,在每个major收集周期中,CMS收集器在收集开始时暂停所有应用程序线程一小段时间,然后在收集中期再次暂停,第二次停顿往往是两次停顿中较长的停顿,在这两个暂停期间,使用多个线程来执行收集工作,包括对活动对象的大多数跟踪标记和对不可访问对象的清除都是通过一个或多个垃圾收集器线程完成的,这些线程与应用程序并发运行,minor收集可以与正在进行的major循环交叉进行,并以类似于并行收集器的方式进行(特别是,应用程序线程在minor收集期间停止)

Concurrent Mode Failure 并发模式失败

The CMS collector uses one or more garbage collector threads that run simultaneously with the application threads with the goal of completing the collection of the tenured generation before it becomes full. As described previously, in normal operation, the CMS collector does most of its tracing and sweeping work with the application threads still running, so only brief pauses are seen by the application threads. However, if the CMS collector is unable to finish reclaiming the unreachable objects before the tenured generation fills up, or if an allocation cannot be satisfied with the available free space blocks in the tenured generation, then the application is paused and the collection is completed with all the application threads stopped. The inability to complete a collection concurrently is referred to as concurrent mode failure and indicates the need to adjust the CMS collector parameters. If a concurrent collection is interrupted by an explicit garbage collection (System.gc()) or for a garbage collection needed to provide information for diagnostic tools, then a concurrent mode interruption is reported.

CMS收集器使用一个或多个垃圾收集器线程,这些线程与应用程序线程同时运行,其目标是在永久代满之前完成对其的收集,如前所述,在正常操作中,CMS收集器在应用程序线程仍然运行的情况下执行大部分跟踪和清除工作,因此,应用程序线程只能看到短暂的暂停,但是,如果CMS收集器无法在永久代被填满之前完成回收不可到达的对象,然后暂停应用程序,完成收集,并停止所有应用程序线程。不能并发地完成收集称为并发模式故障,这表明需要调整CMS收集器参数。如果并发收集被显式垃圾收集(System.gc())或为提供诊断工具所需信息的垃圾收集中断,则会报告并发模式中断。

Excessive GC Time and OutOfMemoryError 超过垃圾收集时间并且内存溢出

The CMS collector throws an OutOfMemoryError if too much time is being spent(花费) in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, then an OutOfMemoryError is thrown. This feature is designed to prevent applications from running for an extended period of time while making little or no progress because the heap is too small. If necessary, this feature can be disabled by adding the option -XX:-UseGCOverheadLimit to the command line.

如果CMS收集器垃圾回收花费太多时间则抛出oom错误,如果垃圾收集超过总时间的98%并且回收的堆大小少于2%,则会抛出oom错误。这个特性的设计是为了防止应用程序由于堆很小,运行很长周期,处理进度很小或没有进展。这个特性可以关闭,通过设置jvm参数:XX:-UseGCOverheadLimit

The policy is the same as that in the parallel collector, except that time spent performing concurrent collections is not counted toward the 98% time limit. In other words, only collections performed while the application is stopped count toward excessive GC time. Such collections are typically due to a concurrent mode failure or an explicit collection request (for example, a call to System.gc).

该策略与并行收集器中的策略相同,只是执行并发收集(应用程序线程和垃圾收集线程都在工作)的时间不计入98%的时间限制,也就是只有应用程序停止的收集时间才计入过多的GC时间(98%),这种收集通常是由于并发模式失败或显式收集请求(例如,对System.gc的调用)造成的。

Floating Garbage 浮动垃圾

The CMS collector, like all the other collectors in Java HotSpot VM, is a tracing collector that identifies at least all the reachable objects in the heap. In the parlance of Richard Jones and Rafael D. Lins in their publication Garbage Collection: Algorithms for Automated Dynamic Memory, it is an incremental update collector. Because application threads and the garbage collector thread run concurrently during a major collection, objects that are traced by the garbage collector thread may subsequently become unreachable by the time collection process ends. Such unreachable objects that have not yet been reclaimed are referred to as floating garbage. The amount of floating garbage depends on the duration of the concurrent collection cycle and on the frequency of reference updates, also known as mutations, by the application. Furthermore, because the young generation and the tenured generation are collected independently, each acts a source of roots to the other. As a rough guideline, try increasing the size of the tenured generation by 20% to account for the floating garbage. Floating garbage in the heap at the end of one concurrent collection cycle is collected during the next collection cycle.

CMS收集器与Java HotSpot VM中的所有其他收集器一样,是一种跟踪收集器,它至少标识堆中所有可访问的对象.用理查德琼斯和拉斐尔D,在他们的出版物《垃圾收集》中;算法自动动态内存,它是一个增量更新收集器,由于应用程序线程和垃圾收集器线程在major收集期间并发运行,垃圾收集器线程跟踪的对象可能在收集过程结束时无法访问。这种尚未回收的不可访问对象称为浮动垃圾。浮动垃圾的数量取决于并发收集周期的持续时间和引用更新的频率,也称为突变,由应用程序。因为年轻代和永久代是独立收集的,每个对象都有彼此的gc root根。作为一个粗略的指导方针,尝试将永久代的大小增加20%,以考虑浮动垃圾。一个并发收集周期结束时堆中的浮动垃圾将在下一个收集周期中收集。

Pauses 停顿

The CMS collector pauses an application twice during a concurrent collection cycle. The first pause is to mark as live the objects directly reachable from the roots (for example, object references from application thread stacks and registers, static objects and so on) and from elsewhere in the heap (for example, the young generation). This first pause is referred to as the initial mark pause. The second pause comes at the end of the concurrent tracing phase and finds objects that were missed by the concurrent tracing due to updates by the application threads of references in an object after the CMS collector had finished tracing that object. This second pause is referred to as the remark pause.

CMS收集器在一个并发收集周期中会暂停应用程序两次。第一次(初始标记阶段)是在标记存活对象(root 可达的对象,例如 静态对象,线程栈。)并且直接访问年轻代的对象。第一个暂停称为初始标记暂停。第二个暂停出现在(重新)并发跟踪阶段的末尾,在CMS收集器完成对对象的跟踪之后,发现由于对象中引用的应用程序线程更新而导致并发跟踪丢失的对象,第二个停顿是叫做 重新标记停顿。

Concurrent Phases 并发时期

The concurrent tracing of the reachable object graph occurs between the initial mark pause and the remark pause. During this concurrent tracing phase one or more concurrent garbage collector threads may be using processor resources that would otherwise have been available to the application. As a result, compute-bound applications may see a commensurate fall in application throughput during this and other concurrent phases even though the application threads are not paused. After the remark pause, a concurrent sweeping phase collects the objects identified as unreachable. Once a collection cycle completes, the CMS collector waits, consuming almost no computational resources, until the start of the next major collection cycle.

并发追踪可达对象发生在初始标记和重新标记之间。在这个并发追踪时期一个或多个并发回收线程也许会使用处理器资源,否则应用程序可以使用这些资源。因此,即使应用程序线程没有暂停(回收线程占用了cpu资源),在此和其他并发阶段,受计算限制的应用程序可能会看到相应的应用程序吞吐量下降。在重新标记阶段暂停之后,一个并发的清除阶段将回收标识为不可到达的对象。收集周期完成后,CMS收集器将等待,几乎不消耗任何计算资源,直到下一个主要收集周期开始。

Starting a Concurrent Collection Cycle 开始一个并发收集周期

With the serial collector a major collection occurs whenever the tenured generation becomes full and all application threads are stopped while the collection is done. In contrast, the start of a concurrent collection must be timed such that the collection can finish before the tenured generation becomes full; otherwise, the application would observe longer pauses due to concurrent mode failure. There are several ways to start a concurrent collection.

对于串行收集器,只要永久代已满,并且在收集完成时停止所有应用程序线程,就会发生major收集,

相反,必须对并发收集的开始进行计时,使收集能够在永久代满之前完成;否则,应用程序将由于并发模式失败而观察到更长的暂停。有几种方法可以启动并发收集。

Based on recent history, the CMS collector maintains estimates of the time remaining before the tenured generation will be exhausted and of the time needed for a concurrent collection cycle. Using these dynamic estimates, a concurrent collection cycle is started with the aim of completing the collection cycle before the tenured generation is exhausted. These estimates are padded for safety, because concurrent mode failure can be very costly.

根据最近的历史记录,CMS收集器维护了预期的剩余时间(在永久代耗尽之前)和并发收集周期所需的时间。

使用这些动态估计,一个并发收集循环就开始了,目的是在永久代耗尽之前完成收集周期。这些估计是为了安全而进行的,因为并发模式失败的代价可能非常大。

根据历史记录,样本估算需要启动并发回收的时机。

A concurrent collection also starts if the occupancy of the tenured generation exceeds an initiating occupancy (a percentage of the tenured generation). The default value for this initiating occupancy threshold is approximately 92%, but the value is subject to change from release to release. This value can be manually adjusted using the command-line option -XX:CMSInitiatingOccupancyFraction=, where is an integral percentage (0 to 100) of the tenured generation size.

如果永久代的占用超过初始占用(永久代的百分比),也会开始并发收集。该初始占用阈值的默认值约为92%,但是该值可能随版本的不同而变化。可以手动调整该参数:-XX:CMSInitiatingOccupancyFraction=(0-100永久代占比)

根据永久代使用占比确定并发回收时机

Scheduling Pauses 调度,计划的停顿

The pauses for the young generation collection and the tenured generation collection occur independently. They do not overlap, but may occur in quick succession such that the pause from one collection, immediately followed by one from the other collection, can appear to be a single, longer pause. To avoid this, the CMS collector attempts to schedule the remark pause roughly midway between the previous and next young generation pauses. This scheduling is currently not done for the initial mark pause, which is usually much shorter than the remark pause.

年轻代收集和永久代收集的停顿是独立发生的,他们不重叠,它们不重叠,但可以快速地连续发生,这样一个收集的暂停,紧接着另一个收集的暂停,可以表现为单个的、更长的暂停。为了避免这种情况,CMS收集器尝试将标记暂停安排在上一个和下一个年轻代暂停之间的中间位置。这种调度目前还没有为初始标记暂停完成,它通常比重新标记暂停短得多。

年轻代,永久代的回收不相互影响,可能存在两个或者多个连续,会导致停顿时机很长的结果。cms则采用了有计划的停顿来避免这种问题,即在年轻代回收暂停之间来标记暂停。

Incremental Mode 增量模式

Note that the incremental mode is being deprecated in Java SE 8 and may be removed in a future major release.

请注意,增量模式在Java SE 8中被弃用,可能在将来的主要版本中被删除。

The CMS collector can be used in a mode in which the concurrent phases are done incrementally. Recall that during a concurrent phase the garbage collector thread is using one or more processors. The incremental mode is meant to lessen the effect of long concurrent phases by periodically stopping the concurrent phase to yield back the processor to the application. This mode, referred to here as i-cms, divides the work done concurrently by the collector into small chunks of time that are scheduled between young generation collections. This feature is useful when applications that need the low pause times provided by the CMS collector are run on machines with small numbers of processors (for example, 1 or 2).

CMS收集器可以在以增量方式完成并发阶段的模式中使用,回想一下,在并发阶段,垃圾收集器线程使用一个或多个处理器,增量模式的目的是通过周期性地停止并发阶段来减少长并发阶段的影响,从而将处理器交还给应用程序。这种模式在这里称为i-cms,它将收集器并发完成的工作划分为小块时间,这些时间安排在年轻代收集之间。当需要CMS收集器提供的低暂停时间的应用程序在处理器数量较少的机器(如1到2个)上运行时,此功能非常有用。

cms会使用cpu资源,如果是1到两个cpu的情况,则应用程序停顿会很明显,资源紧张,cms通过使用将并发收集阶段的工作分割成多个阶段完成来避免这种问题,这个叫做i-cms模式,增量模式。

The concurrent collection cycle typically includes the following steps:

并发收集周期通常包括以下步骤:

  • 【初始标记】Stop all application threads, identify the set of objects reachable from roots, and then resume all application threads. 停止所有应用程序线程,确定从根目录可以访问的对象集,然后恢复所有应用程序线程。
  • 【并发标记】Concurrently trace the reachable object graph, using one or more processors, while the application threads are executing. 在应用程序线程执行时,(与应用程序一起并发)使用一个或多个处理器并发地跟踪可到达的对象图。
  • Concurrently retrace sections of the object graph that were modified since the tracing in the previous step, using one processor. 使用一个处理器,同时回滚上一步跟踪之后修改的对象图部分。
  • 【重新标记】Stop all application threads and retrace sections of the roots and object graph that may have been modified since they were last examined, and then resume all application threads. 停止所有应用程序线程,并重新跟踪根和对象图的部分,这些部分可能在最后一次检查后被修改,然后恢复所有应用程序线程。
  • 【并发清除】Concurrently sweep up the unreachable objects to the free lists used for allocation, using one processor. 使用一个处理器并发(与应用程序一起并发处理)地将不可到达的对象清除到用于分配的空闲列表。
  • 【并发重置】Concurrently resize the heap and prepare the support data structures for the next collection cycle, using one processor. 使用一个处理器,同时调整堆的大小并为下一个收集周期准备支持数据结构。

Normally, the CMS collector uses one or more processors during the entire concurrent tracing phase, without voluntarily relinquishing them. Similarly, one processor is used for the entire concurrent sweep phase, again without relinquishing it. This overhead can be too much of a disruption for applications with response time constraints that might otherwise have used the processing cores, particularly when run on systems with just one or two processors. Incremental mode solves this problem by breaking up the concurrent phases into short bursts of activity, which are scheduled to occur midway between minor pauses.

通常,CMS收集器在整个并发跟踪阶段使用一个或多个处理器,而不会主动放弃它们。类似地,在整个并发清理阶段使用一个处理器,同样不放弃它。对于具有响应时间约束的应用程序来说,这种开销可能会造成太大的干扰,可能会使用处理内核,特别是在只有一个或两个处理器的系统上运行时。增量模式通过将并发阶段分解为活动的短时间爆发来解决这个问题,这些活动计划在小暂停之间进行。

The i-cms mode uses a duty cycle to control the amount of work the CMS collector is allowed to do before voluntarily giving up the processor. The duty cycle is the percentage of time between young generation collections that the CMS collector is allowed to run. The i-cms mode can automatically compute the duty cycle based on the behavior of the application (the recommended method, known as automatic pacing), or the duty cycle can be set to a fixed value on the command line.

i-cms模式使用一个占空比来控制CMS收集器在主动放弃处理器之前允许做的工作量。占空比是允许CMS收集器运行的年轻代收集之间的时间百分比。i-cms模式可以根据应用程序的行为自动计算占空比。或者通过固定值设置该占比。

Command-Line Options 命令行参数

Table 8-1, "Command-Line Options for i-cms" list command-line options that control the i-cms mode. The section Recommended Options suggests an initial set of options.

Option Description Default Value, Java SE 5 and Earlier Default Value, Java SE 6 and Later
-XX:+CMSIncrementalMode Enables incremental mode. Note that the CMS collector must also be enabled (with -XX:+UseConcMarkSweepGC) for this option to work. disabled disabled
-XX:+CMSIncrementalPacing Enables automatic pacing. The incremental mode duty cycle is automatically adjusted based on statistics collected while the JVM is running. disabled disabled
-XX:CMSIncrementalDutyCycle= The percentage (0 to 100) of time between minor collections that the CMS collector is allowed to run. If CMSIncrementalPacing is enabled, then this is just the initial value. 50 10
-XX:CMSIncrementalDutyCycleMin= The percentage (0 to 100) that is the lower bound on the duty cycle when CMSIncrementalPacing is enabled. 10 0
-XX:CMSIncrementalSafetyFactor= The percentage (0 to 100) used to add conservatism when computing the duty cycle 10 10
-XX:CMSIncrementalOffset= The percentage (0 to 100) by which the incremental mode duty cycle is shifted to the right within the period between minor collections. 0 0
-XX:CMSExpAvgFactor= The percentage (0 to 100) used to weight the current sample when computing exponential averages for the CMS collection statistics. 25 25

Recommended Options

To use i-cms in Java SE 8, use the following command-line options:

-XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode  -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

The first two options enable the CMS collector and i-cms, respectively. The last two options are not required; they simply cause diagnostic information about garbage collection to be written to standard output, so that garbage collection behavior can be seen and later analyzed.

For Java SE 5 and earlier releases, Oracle recommends using the following as an initial set of command-line options for i-cms:

-XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode \ -XX:+PrintGCDetails -XX:+PrintGCTimeStamps \ -XX:+CMSIncrementalPacing -XX:CMSIncrementalDutyCycleMin=0 -XX:CMSIncrementalDutyCycle=10

The same values are recommended for JavaSE8 although the values for the three options that control i-cms automatic pacing became the default in JavaSE6.

Basic Troubleshooting

The i-cms automatic pacing feature uses statistics gathered while the program is running to compute a duty cycle so that concurrent collections complete before the heap becomes full. However, past behavior is not a perfect predictor of future behavior and the estimates may not always be accurate enough to prevent the heap from becoming full. If too many full collections occur, then try the steps in Table 8-2, "Troubleshooting the i-cms Automatic Pacing Feature", one at a time.

Table 8-2 Troubleshooting the i-cms Automatic Pacing Feature

Step Options
1. Increase the safety factor. -XX:CMSIncrementalSafetyFactor=
2. Increase the minimum duty cycle. -XX:CMSIncrementalDutyCycleMin=
3. Disable automatic pacing and use a fixed duty cycle. -XX:-CMSIncrementalPacing -XX:CMSIncrementalDutyCycle=

Measurements

Example 8-1, "Output from the CMS Collector" is the output from the CMS collector with the options -verbose:gc and -XX:+PrintGCDetails, with a few minor details removed. Note that the output for the CMS collector is interspersed with the output from the minor collections; typically many minor collections occur during a concurrent collection cycle. CMS-initial-mark indicates the start of the concurrent collection cycle, CMS初始标记表明并发收集周期的开始,CMS-concurrent-mark indicates the end of the concurrent marking phase, 并发标记表明并发标记阶段的结束,and CMS-concurrent-sweep marks the end of the concurrent sweeping phase. 并发清理标记表明并发清理阶段的结束。Not discussed previously is the precleaning phase indicated by CMS-concurrent-preclean. Precleaning represents work that can be done concurrently in preparation for the remark phase CMS-remark. The final phase is indicated by CMS-concurrent-reset and is in preparation for the next concurrent collection.最终的接口是表明cms并发重置并且是下一个并发采集的预备。

CMS GC日志

Example 8-1 Output from the CMS Collector

[GC [1 CMS-initial-mark: 13991K(20288K)] 14103K(22400K), 0.0023781 secs] [GC [DefNew: 2112K->64K(2112K), 0.0837052 secs] 16103K->15476K(22400K), 0.0838519 secs] ... [GC [DefNew: 2077K->63K(2112K), 0.0126205 secs] 17552K->15855K(22400K), 0.0127482 secs] [CMS-concurrent-mark: 0.267/0.374 secs] [GC [DefNew: 2111K->64K(2112K), 0.0190851 secs] 17903K->16154K(22400K), 0.0191903 secs] [CMS-concurrent-preclean: 0.044/0.064 secs] [GC [1 CMS-remark: 16090K(20288K)] 17242K(22400K), 0.0210460 secs] [GC [DefNew: 2112K->63K(2112K), 0.0716116 secs] 18177K->17382K(22400K), 0.0718204 secs] [GC [DefNew: 2111K->63K(2112K), 0.0830392 secs] 19363K->18757K(22400K), 0.0832943 secs] ... [GC [DefNew: 2111K->0K(2112K), 0.0035190 secs] 17527K->15479K(22400K), 0.0036052 secs] [CMS-concurrent-sweep: 0.291/0.662 secs] [GC [DefNew: 2048K->0K(2112K), 0.0013347 secs] 17527K->15479K(27912K), 0.0014231 secs] [CMS-concurrent-reset: 0.016/0.016 secs] [GC [DefNew: 2048K->1K(2112K), 0.0013936 secs] 17527K->15479K(27912K), 0.0014814 secs ]

The initial mark pause is typically short relative to the minor collection pause time. The concurrent phases (concurrent mark, concurrent preclean and concurrent sweep) normally last significantly longer than a minor collection pause, as indicated by Example 8-1, "Output from the CMS Collector". Note, however, that the application is not paused during these concurrent phases. The remark pause is often comparable in length to a minor collection. The remark pause is affected by certain application characteristics (for example, a high rate of object modification can increase this pause) and the time since the last minor collection (for example, more objects in the young generation may increase this pause).

相关文章
|
4月前
|
算法 Java
「译文」Java 垃圾收集参考手册(四):Serial GC
「译文」Java 垃圾收集参考手册(四):Serial GC
|
4月前
|
算法 Java PHP
「译文」Java 垃圾收集参考手册(一):垃圾收集简介
「译文」Java 垃圾收集参考手册(一):垃圾收集简介
|
4月前
|
存储 算法 Java
深入浅出JVM(十七)之并发垃圾收集器CMS
深入浅出JVM(十七)之并发垃圾收集器CMS
|
4月前
|
监控 Java Linux
JVM工作原理与实战(三十七):Shenandoah GC和ZGC
JVM作为Java程序的运行环境,其负责解释和执行字节码,管理内存,确保安全,支持多线程和提供性能监控工具,以及确保程序的跨平台运行。本文主要介绍了垃圾回收器的技术演进、Shenandoah GC、ZGC等内容。
66 0
|
4月前
|
算法 安全 Java
「译文」Java 垃圾收集参考手册(三):GC 算法基础篇
「译文」Java 垃圾收集参考手册(三):GC 算法基础篇
|
4月前
|
算法 Java
「译文」Java 垃圾收集参考手册(六):Concurrent Mark and Sweep
「译文」Java 垃圾收集参考手册(六):Concurrent Mark and Sweep
|
4月前
|
算法 Java
「译文」Java 垃圾收集参考手册(五):Parallel GC
「译文」Java 垃圾收集参考手册(五):Parallel GC
|
4月前
|
存储 算法 Java
「译文」Java 垃圾收集参考手册(七):Garbage First
「译文」Java 垃圾收集参考手册(七):Garbage First
|
4月前
|
监控 算法 数据可视化
「译文」Java 垃圾收集参考手册(十):GC 调优工具篇
「译文」Java 垃圾收集参考手册(十):GC 调优工具篇