转载自 ---- http://www.blogjava.net/killme2008/archive/2009/09/22/296085.html
在初步确定CMS参数后,系统运行了几天,今天尝试在线上打开了GC日志,按阿宝同学的说法是gc日志的开销比之jstat还小,打开之后发现确实影响很小。打开GC日志之后又发现几个隐藏的问题比较有价值,这里记录下。
首先是系统在启动的时候有一次System.gc()调用引起的full gc,日志输出类似这样:
1.201
: [Full GC (System)
1.201
: [CMS: 0K
->
797K(1310720K),
0.1090540
secs] 29499K
->
797K(1546688K), [CMS Perm : 5550K
->
5547K(65536K)],
0.1091860
secs] [Times: user
=
0.05
sys
=
0.06
, real
=
0.11
secs]
可以确认的是我们系统里的代码绝对没有调用System.gc()方法,但是不保证第三方代码有调用,通过搜索代码引用,后来定位到了mina的ByteBuffer创建上面。Mina 1.1封装的ByteBuffer的allocate()方法默认创建的是Direct ByteBuffer
,而DirectByteBuffer的构造函数里调用了
Bits.reserveMemory(cap);
这个方法强制调用了System.gc():
static
void
reserveMemory(
long
size) {
synchronized
(Bits.
class
) {
if
(
!
memoryLimitSet
&&
VM.isBooted()) {
maxMemory
=
VM.maxDirectMemory();
memoryLimitSet
=
true
;
}
if
(size
<=
maxMemory
-
reservedMemory) {
reservedMemory
+=
size;
return
;
}
}
System.gc();
try
{
Thread.sleep(
100
);
}
catch
(InterruptedException x) {
//
Restore interrupt status
Thread.currentThread().interrupt();
}
synchronized
(Bits.
class
) {
if
(reservedMemory
+
size
>
maxMemory)
throw
new
OutOfMemoryError(
"
Direct buffer memory
"
);
reservedMemory
+=
size;
}
}
调用这个方法是为了用户对Direct ByteBuffer的内存可控。而在我们系统中使用的通讯层初始化Decoder的时候通过Mina
1.1创建了一个Direct ByteBuffer,导致了这一次强制的full
gc。这个Buffer因为是长期持有的,因此创建Direct类型也还可以接受。
但是在这次GC后,又发现每隔一个小时就有一次System.gc()引起的full gc,这就太难以忍受了,日志大概是这样,注意间隔时间都是3600秒左右:
10570.672
: [Full GC (System)
10570.672
: [CMS: 779199K
->
107679K(1310720K),
1.2957430
secs] 872163K
->
107679K(1546688K), [CMS Perm : 23993K
->
15595K(65536K)],
1.2959630
secs] [Times: user
=
1.27
sys
=
0.02
, real
=
1.30
secs]
14171.971
: [Full GC (System)
14171.971
: [CMS: 680799K
->
83681K(1310720K),
1.0171580
secs] 836740K
->
83681K(1546688K), [CMS Perm : 20215K
->
15599K(65536K)],
1.0173850
secs] [Times: user
=
0.97
sys
=
0.01
, real
=
1.02
secs]
17774.020
: [Full GC (System)
17774.020
: [CMS: 676201K
->
79331K(1310720K),
0.9652670
secs] 817596K
->
79331K(1546688K), [CMS Perm : 22808K
->
15619K(65536K)],
0.9655150
secs] [Times: user
=
0.93
sys
=
0.02
, real
=
0.97
secs]
21374.989
: [Full GC (System)
21374.989
: [CMS: 677818K
->
78590K(1310720K),
0.9297080
secs] 822317K
->
78590K(1546688K), [CMS Perm : 16435K
->
15593K(65536K)],
0.9299620
secs] [Times: user
=
0.89
sys
=
0.01
, real
=
0.93
secs]
24976.948
: [Full GC (System)
24976.948
: [CMS: 659511K
->
77608K(1310720K),
0.9255360
secs] 794004K
->
77608K(1546688K), [CMS Perm : 22359K
->
15594K(65536K)],
0.9257760
secs] [Times: user
=
0.88
sys
=
0.02
, real
=
0.93
secs]
28578.892
: [Full GC (System)
28578.892
: [CMS: 562058K
->
77572K(1310720K),
0.8365500
secs] 735072K
->
77572K(1546688K), [CMS Perm : 15840K
->
15610K(65536K)],
0.8367990
secs] [Times: user
=
0.82
sys
=
0.00
, real
=
0.84
secs]
32179.731
: [Full GC (System)
32179.732
: [CMS: 549874K
->
77224K(1310720K),
0.7864400
secs] 561803K
->
77224K(1546688K), [CMS Perm : 16016K
->
15597K(65536K)],
0.7866540
secs] [Times: user
=
0.75
sys
=
0.01
, real
=
0.79
secs]
搜遍了源码和依赖库,没有再发现显式的gc调用,问题只能出在运行时上,突然想起我们的系统使用RMI暴露JMX给监控程序,监控程序通过RMI连接JMX监控系统和告警等,会不会是RMI的分布式垃圾收集
导致的?果然,一查资料,RMI的分布式收集会强制调用System.gc()来进行分布式GC,server端的间隔恰好是一个小时,这个参数可以通过:
-
Dsun.rmi.dgc.server.gcInterval
=
3600000
来调整。调长时间是一个解决办法,但是我们更希望能不出现显式的GC调用,禁止显式GC调用通过-XX:+DisableExplicitGC
是一个办法,但是禁止了分布式GC会导致什么问题却是心理没底,毕竟我们的JMX调用还是很频繁的,幸运的是JDK6还提供了另一个选项
-XX:+ExplicitGCInvokesConcurrent
,允许System.gc()也并发运行,调整DGC时间间隔加上这个选项双管齐下彻底解决了full gc的隐患。
打开GC日志后发现的另一个问题是remark的时间过长,已经启用了并行remark,但是时间还是经常超过200毫秒,这个可能的原因有两个:我们的
年老代太大或者触发CMS的阀值太高了,CMS进行的时候年老代里的对象已经太多。初步的计划是调小-XX:SurvivorRatio增大救助空间并且
降低-XX:CMSInitiatingOccupancyFraction这个阀值。此外,还找到另一个可选参数-XX:+CMSScavengeBeforeRemark
,启用这个选项后,强制remark之前开始一次minor gc,减少remark的暂停时间,但是在remark之后也将立即开始又一次相对较长时间minor gc,如果你的minor gc很快的话可以考虑下这个选项,暂未实验。
分享到:
相关推荐
Java虚拟机(JVM)垃圾回收(GC)是Java语言内存管理的核心机制,负责回收Java堆内存中不再使用的对象所占的空间。...通过实践中不断尝试和调整,开发者可以为自己的应用找到最佳的GC配置,以达到最优的性能表现。
- CMS(Concurrent Mark Sweep)GC:并行标记,低延迟,适用于响应时间敏感的应用。 - G1(Garbage-First)GC:新一代的垃圾收集器,目标是达到可预测的暂停时间。 4. GC调优 调优主要涉及选择合适的垃圾收集器...
本文将从 JVM 和 GC 相关参数、问题解决过程、排除应用程序的内存使用问题、排除 Cache 内容过多的问题、调整 GC 时间点、调整对象在年轻代内存中驻留的时间、CMS Remark之前强制进行年轻代的 GC 等几个方面详细介绍...
例如,调整新生代和老年代的比例,选择合适的垃圾收集器(如Serial GC、Parallel GC、CMS GC、G1 GC等),以及设置适当的内存大小和暂停时间目标等,都是GC调优的重要方面。 在备考GC程序员考试时,考生需要掌握...
此外,监控GC日志,分析GC行为,以及使用适当的GC算法(如CMS、G1或ZGC)也是优化过程中的关键步骤。通过这些实践,开发者能够确保Java应用程序在运行时具有良好的内存管理和高效的资源利用率。
3. **并行与并发设置**:调整并行GC线程数和并发GC策略,优化性能。 4. **对象存活率预估**:通过调整Survivor区比例,减少Full GC的发生。 5. **内存分配策略**:如使用CMS或G1等高级GC算法,降低STW影响。 此外,...
**JVM参数调整**:通过设置JVM参数可以影响GC行为,如`-Xms`和`-Xmx`控制堆内存大小,`-XX:NewRatio`设置新生代与老年代的比例,`-XX:MaxPermSize`或`-XX:MetaspaceSize`控制方法区大小,`-XX:+UseConcMarkSweepGC`...
4. **GC性能调优**:如何通过调整JVM参数来优化垃圾收集的性能,减少停顿时间,提高应用程序响应速度。 5. **内存泄漏与内存溢出**:理解这两个问题的原因和解决方法,以及如何通过分析工具检测它们。 6. **垃圾...
3. **并发标记GC(Concurrent Mark Sweep, CMS)**:CMS旨在减少STW的时间,它将大部分GC工作与应用程序执行并发进行,只在开始和结束时有短暂的暂停。 4. **G1 GC(Garbage-First)**:G1是一种区域化GC,目标是...
6. **并行与并发调整**:根据系统硬件资源调整并行GC的线程数(`-XX:ParallelGCThreads`),以及并发GC的并发程度(`-XX:ConcGCThreads`),以达到最佳性能。 7. **类加载器管理**:类加载器的不当使用可能导致内存...
- 调整GC参数:例如,CMS中的`-XX:CMSInitiatingOccupancyFraction`用来设置触发CMS的阈值。 - 监控GC状态:使用JVisualVM、JConsole等工具监控GC性能,分析GC日志,找出问题。 GC工具方面,JDK自带了一些工具帮助...
在Java世界中,JVM(Java虚拟机)是运行所有Java应用程序的核心,它负责解析字节码、管理内存以及执行线程。...通过实践和研究GC算法及种类,开发者能更有效地管理内存,使Java应用程序运行更加高效。
6. **比较分析**:对比不同配置或不同时间段的GC日志,找出最佳实践。 为了有效地使用这类工具,你需要了解一些基本的JVM内存管理概念,如新生代、老年代、永久代(对于较旧的JVM)或元空间(对于Java 8及以上版本...
在Java编程语言中,垃圾回收(Garbage Collection, GC)是一项至关重要的机制,它自动...通过深入理解GC的工作原理,调整合适的GC策略,以及优化代码,开发者可以提升应用的性能和稳定性,成为一名真正的Java GC专家。
JVM提供了多种垃圾回收器供选择,如Serial GC、Parallel GC、CMS GC等。开发者可以根据应用的特点选择合适的垃圾回收器,并通过JVM参数进行配置,以达到提升性能的目的。 最后,手册强调,在生产环境中应用JVM参数...
1. **GC算法分析**:GC-PowerStation可能提供对多种垃圾收集算法的详细分析,如Serial、Parallel、CMS(Concurrent Mark Sweep)、G1(Garbage-First)和ZGC(Zing Garbage Collector)等。每种算法都有其适用场景和...
【HotSpot GC官网文档...这个文档集合对于深入理解Java垃圾收集机制,特别是HotSpot JVM中的GC工作原理和调优实践具有很高的参考价值。通过这些截图,开发者可以获得关于如何选择、配置和优化垃圾收集器的宝贵信息。
2. **GC算法**:介绍常用的垃圾收集算法,如Serial、Parallel、CMS(Concurrent Mark Sweep)和G1(Garbage-First)等,分析它们的特点和适用场景。 3. **内存区域和大小配置**:讨论堆内存的结构,如Eden区、...
2. **垃圾收集器类型**:Java中有多种GC实现,如Serial GC、Parallel GC、CMS(Concurrent Mark Sweep)、G1(Garbage First)和ZGC(Z Garbage Collector)。每种都有其特定的设计目标和适用场景,比如Serial适合轻...