[转载]理解 CMS GC 日志

本文详细解读了CMS垃圾回收日志中的各项指标,包括年轻代和持久代的收集情况、标记-清除-压缩阶段的性能分析以及并发模式失败的原因。通过案例展示了如何识别和避免垃圾回收过程中的问题,以提升应用性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CMS GC with -XX:+PrintGCDetails and -XX:+PrintGCTimeStamps prints a lot of information. Understanding this information can help in fine tuning various parameters of the application and CMS to achieve best performance.

Let's have a look at some of the CMS logs generated with 1.4.2_10:

39.910: [GC 39.910: [ParNew: 261760K->0K(261952K), 0.2314667 secs] 262017K->26386K(1048384K), 0.2318679 secs]

Young generation (ParNew) collection. Young generation capacity is 261952K and after the collection its occupancy drops down from 261760K to 0. This collection took 0.2318679 secs.

40.146: [GC [1 CMS-initial-mark: 26386K(786432K)] 26404K(1048384K), 0.0074495 secs]

Beginning of tenured generation collection with CMS collector. This is initial Marking phase of CMS where all the objects directly reachable from roots are marked and this is done with all the mutator threads stopped.

Capacity of tenured generation space is 786432K and CMS was triggered at the occupancy of 26386K.

40.154: [CMS-concurrent-mark-start]

Start of concurrent marking phase.
In Concurrent Marking phase, threads stopped in the first phase are started again and all the objects transitively reachable from the objects marked in first phase are marked here.

40.683: [CMS-concurrent-mark: 0.521/0.529 secs]

Concurrent marking took total 0.521 seconds cpu time and 0.529 seconds wall time that includes the yield to other threads also.

40.683: [CMS-concurrent-preclean-start]

Start of precleaning.
Precleaning is also a concurrent phase. Here in this phase we look at the objects in CMS heap which got updated by promotions from young generation or new allocations or got updated by mutators while we were doing the concurrent marking in the previous concurrent marking phase. By rescanning those objects concurrently, the precleaning phase helps reduce the work in the next stop-the-world “remark” phase.

40.701: [CMS-concurrent-preclean: 0.017/0.018 secs]

Concurrent precleaning took 0.017 secs total cpu time and 0.018 wall time.

40.704: [GC40.704: [Rescan (parallel) , 0.1790103 secs]40.883: [weak refs processing, 0.0100966 secs] [1 CMS-remark: 26386K(786432K)] 52644K(1048384K), 0.1897792 secs]

Stop-the-world phase. This phase rescans any residual updated objects in CMS heap, retraces from the roots and also processes Reference objects. Here the rescanning work took 0.1790103 secs and weak reference objects processing took 0.0100966 secs. This phase took total 0.1897792 secs to complete.

40.894: [CMS-concurrent-sweep-start]

Start of sweeping of dead/non-marked objects. Sweeping is concurrent phase performed with all other threads running.

41.020: [CMS-concurrent-sweep: 0.126/0.126 secs]

Sweeping took 0.126 secs.

41.020: [CMS-concurrent-reset-start]

Start of reset.

41.147: [CMS-concurrent-reset: 0.127/0.127 secs]

In this phase, the CMS data structures are reinitialized so that a new cycle may begin at a later time. In this case, it took 0.127 secs.

This was how a normal CMS cycle runs. Now let us look at some other CMS log entries:

197.976: [GC 197.976: [ParNew: 260872K->260872K(261952K), 0.0000688 secs]197.976: [CMS197.981: [CMS-concurrent-sweep: 0.516/0.531 secs]
(concurrent mode failure): 402978K->248977K(786432K), 2.3728734 secs] 663850K->248977K(1048384K), 2.3733725 secs]

This shows that a ParNew collection was requested, but it was not attempted because it was estimated that there was not enough space in the CMS generation to promote the worst case surviving young generation objects. We name this failure as “full promotion guarantee failure”.

Due to this, Concurrent Mode of CMS is interrupted and a Full GC is invoked at 197.981. This mark-sweep-compact stop-the-world Full GC took 2.3733725 secs and the CMS generation space occupancy dropped from 402978K to 248977K.

The concurrent mode failure can either be avoided by increasing the tenured generation size or initiating the CMS collection at a lesser heap occupancy by setting CMSInitiatingOccupancyFraction to a lower value and setting UseCMSInitiatingOccupancyOnly to true. The value for CMSInitiatingOccupancyFraction should be chosen appropriately because setting it to a very low value will result in too frequent CMS collections.

Sometimes we see these promotion failures even when the logs show that there is enough free space in tenured generation. The reason is 'fragmentation' - the free space available in tenured generation is not contiguous, and promotions from young generation require a contiguous free block to be available in tenured generation. CMS collector is a non-compacting collector, so can cause fragmentation of space for some type of applications. In his blog, Jon talks in detail on how to deal with this fragmentation problem:
http://blogs.sun.com/roller/page/jonthecollector?entry=when_the_sum_of_the

Starting with 1.5, for the CMS collector, the promotion guarantee check is done differently. Instead of assuming that the promotions would be worst case i.e. all of the surviving young generation objects would get promoted into old gen, the expected promotion is estimated based on recent history of promotions. This estimation is usually much smaller than the worst case promotion and hence requires less free space to be available in old generation. And if the promotion in a scavenge attempt fails, then the young generation is left in a consistent state and a stop-the-world mark-compact collection is invoked. To get the same functionality with UseSerialGC you need to explicitly specify the switch -XX:+HandlePromotionFailure.

283.736: [Full GC 283.736: [ParNew: 261599K->261599K(261952K), 0.0000615 secs] 826554K->826554K(1048384K), 0.0003259 secs]
GC locker: Trying a full collection because scavenge failed
283.736: [Full GC 283.736: [ParNew: 261599K->261599K(261952K), 0.0000288 secs]

Stop-the-world GC happening when a JNI Critical section is released. Here again the young generation collection failed due to “full promotion guarantee failure” and then the Full GC is being invoked.

CMS can also be run in incremental mode (i-cms), enabled with -XX:+CMSIncrementalMode. In this mode, CMS collector does not hold the processor for the entire long concurrent phases but periodically stops them and yields the processor back to other threads in application. It divides the work to be done in concurrent phases in small chunks(called duty cycle) and schedules them between minor collections. This is very useful for applications that need low pause times and are run on machines with small number of processors.

Some logs showing the incremental CMS.

2803.125: [GC 2803.125: [ParNew: 408832K->0K(409216K), 0.5371950 secs] 611130K->206985K(1048192K) icms_dc=4 , 0.5373720 secs]
2824.209: [GC 2824.209: [ParNew: 408832K->0K(409216K), 0.6755540 secs] 615806K->211897K(1048192K) icms_dc=4 , 0.6757740 secs]

Here, the scavenges took respectively 537 ms and 675 ms. In between these two scavenges, iCMS ran for a brief period as indicated by the icms_dc value, which indicates a duty-cycle. In this case the duty cycle was 4%. A simple calculation shows that the iCMS incremental step lasted for 4/100 \* (2824.209 - 2803.125 - 0.537) = 821 ms, i.e. 4% of the time between the two scavenges.

Starting with 1.5, CMS has one more phase – concurrent abortable preclean. Abortable preclean is run between a 'concurrent preclean' and 'remark' until we have the desired occupancy in eden. This phase is added to help schedule the 'remark' phase so as to avoid back-to-back pauses for a scavenge closely followed by a CMS remark pause. In order to maximally separate a scavenge from a CMS remark pause, we attempt to schedule the CMS remark pause roughly mid-way between scavenges.

There is a second reason why we do this. Immediately following a scavenge there are likely a large number of grey objects that need rescanning. The abortable preclean phase tries to deal with such newly grey objects thus reducing a subsequent CMS remark pause.

The scheduling of 'remark' phase can be controlled by two jvm options CMSScheduleRemarkEdenSizeThreshold and CMSScheduleRemarkEdenPenetration. The defaults for these are 2m and 50% respectively. The first parameter determines the Eden size below which no attempt is made to schedule the CMS remark pause because the pay off is expected to be minuscule. The second parameter indicates the Eden occupancy at which a CMS remark is attempted.

After 'concurrent preclean' if the Eden occupancy is above CMSScheduleRemarkEdenSizeThreshold, we start 'concurrent abortable preclean' and continue precleanig until we have CMSScheduleRemarkEdenPenetration percentage occupancy in eden, otherwise we schedule 'remark' phase immediately.

7688.150: [CMS-concurrent-preclean-start]
7688.186: [CMS-concurrent-preclean: 0.034/0.035 secs]
7688.186: [CMS-concurrent-abortable-preclean-start]
7688.465: [GC 7688.465: [ParNew: 1040940K->1464K(1044544K), 0.0165840 secs] 1343593K->304365K(2093120K), 0.0167509 secs]
7690.093: [CMS-concurrent-abortable-preclean: 1.012/1.907 secs]
7690.095: [GC[YG occupancy: 522484 K (1044544 K)]7690.095: [Rescan (parallel) , 0.3665541 secs]7690.462: [weak refs processing, 0.0003850 secs] [1 CMS-remark: 302901K(1048576K)] 825385K(2093120K), 0.3670690 secs]

In the above log, after a preclean, 'abortable preclean' starts. After the young generation collection, the young gen occupancy drops down from 1040940K to 1464K. When young gen occupancy reaches 522484K which is 50% of the total capacity, precleaning is aborted and 'remark' phase is started.

Note that in 1.5, young generation occupancy also gets printed in the final remark phase.

For more detailed information and tips on GC tuning, please refer to the following documents:
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
http://java.sun.com/docs/hotspot/gc1.4.2/

官方地址:

http://blogs.oracle.com/poonam/entry/understanding_cms_gc_logs

<think>嗯,用户想了解主流J2EE应用服务器的配置方法和性能调优技巧,特别是WebLogic、JBoss和Tomcat。首先,我需要回忆一下这些应用服务器的基本区别和各自的特性。根据引用内容,Tomcat主要支持Servlet和JSP,而JBoss和WebLogic是功能更全的应用服务器,支持EJB等J2EE特性。 接下来,配置方法方面,可能需要分每个服务器来说。比如Tomcat的配置通常涉及server.xml和web.xml,调整线程池、连接器参数。而JBoss和WebLogic可能有更复杂的配置,比如子系统设置和集群配置。调优的话,内存管理、线程池调整、缓存机制都是关键点。引用里提到JBoss和Tomcat集成可以实现全部J2EE功能,这可能涉及到集群配置,如引用3中提到的群集技术对扩展性的重要性。 然后,性能调优需要考虑JVM参数,比如堆大小、垃圾回收策略。WebLogic可能有自己的调优工具,JBoss的子系统优化,比如EJB池大小。Tomcat作为轻量级服务器,可能需要优化连接器参数,比如maxThreads和acceptCount。另外,缓存策略也很重要,比如静态资源缓存和会话复制。 用户可能还希望知道具体的最佳实践,比如如何监控服务器性能,使用哪些工具,或者常见的配置错误。需要确保每个服务器的调优方法分开说明,同时比较它们的异同。比如引用2提到Tomcat与JBoss集成,这可能是一个优化方案,而引用4的比较分析可能提供更多细节。 还要注意引用来源的可信度,比如引用4是转载的博客,可能需要谨慎处理。但其他引用如1、2、3看起来来自技术分析文章,比较可靠。最后,生成的相关问题要围绕配置、调优、监控和比较,帮助用户深入理解。</think>### 主流 J2EE 应用服务器配置与调优实践 #### 一、WebLogic 配置与调优 1. **核心配置** - **内存分配**:通过修改 `setDomainEnv.sh`(Linux)或 `setDomainEnv.cmd`(Windows)调整 JVM 堆大小,例如: ```bash -Xms4096m -Xmx8192m -XX:MaxPermSize=2048m ``` - **线程池优化**:在管理控制台中调整“执行线程数”(默认 16),根据并发量设置 `MaxThreads` 和 `MinThreads`,避免线程竞争[^3]。 - **数据源连接池**:配置 `Initial Capacity` 和 `Max Capacity`,启用连接泄漏检测(`Test Connections on Reserve`)。 2. **性能调优** - **启用集群**:通过横向扩展提升负载能力,配置会话复制(如内存复制或数据库持久化)。 - **缓存优化**:启用 `WebLogic 二级缓存`,调整 `Cache Size` 和 `Cache Timeout`。 - **垃圾回收策略**:使用 G1 或 CMS 垃圾收集器,减少 Full GC 频率。 --- #### 二、JBoss 配置与调优 1. **核心配置** - **子系统优化**:在 `standalone.xml` 中调整 `web` 子系统的 `max-connections` 和 `worker线程池`。 - **内存管理**:修改 `standalone.conf` 设置堆内存,例如: ```bash -Xmx4g -XX:MetaspaceSize=256m ``` - **EJB 池配置**:调整 `ejb3` 子系统的 `max-pool-size`,避免资源耗尽。 2. **性能调优** - **分布式缓存**:集成 Infinispan 缓存,配置分布式会话存储[^1]。 - **JVM 参数优化**:启用压缩指针(`-XX:+UseCompressedOops`)和分层编译(`-XX:+TieredCompilation`)。 - **日志优化**:关闭 DEBUG 日志级别,减少 I/O 开销。 --- #### 三、Tomcat 配置与调优 1. **核心配置** - **连接器优化**:在 `server.xml` 中调整 `Connector` 参数: ```xml <Connector port="8080" maxThreads="200" acceptCount="100" /> ``` - **内存设置**:修改 `catalina.sh` 设置堆内存: ```bash -Xms512m -Xmx2048m ``` - **会话持久化**:配置 `Manager` 组件实现会话存储(如 Redis)。 2. **性能调优** - **静态资源缓存**:启用 `DefaultServlet` 的 `cacheMaxSize` 和 `cacheTTL`。 - **NIO 模式**:使用 `org.apache.coyote.http11.Http11NioProtocol` 提升并发处理能力[^2]。 - **关闭自动重载**:设置 `reloadable="false"` 避免类重复加载。 --- #### 四、通用优化原则 1. **监控工具**:使用 VisualVM、JConsole 或 Prometheus + Grafana 监控 JVM 状态。 2. **压测验证**:通过 JMeter 或 Gatling 模拟高并发场景,定位瓶颈。 3. **集群部署**:结合负载均衡(如 Nginx)实现横向扩展[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值