通过Java/JMX得到full GC次数
2016-07-11 10:20
696 查看
今天有个同事问如何能通过JMX获取到某个Java进程的full
GC次数:
引用
hi,问个问题,怎们在java中获取到full gc的次数呢?
我现在用jmx的那个得到了gc次数,不过不能细化出来full gc的次数
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
for (final GarbageCollectorMXBean garbageCollector
: ManagementFactory.getGarbageCollectorMXBeans()) {
gcCounts += garbageCollector.getCollectionCount();
}
你比如我现在是这样拿次数的
我回答说因为full GC概念只有在分代式GC的上下文中才存在,而JVM并不强制要求GC使用分代式实现,所以JMX提供的标准MXBean API里不提供“full
GC次数”这样的方法也正常。
既然“full GC”本来就是非常平台相关的概念,那就hack一点,用平台相关的代码来解决问题好了。这些GC的MXBean都是有名字的,而主流的JVM的GC名字相对稳定,非要通过JMX得到full GC次数的话,用名字来判断一下就好了。
举个例子来看看。通过JDK 6自带的JConsole工具来查看相关的MXBean的话,可以看到,
GC的MXBean在这个位置:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202007/31/bbd368f1878d0ca3f92ef718e4514000.png)
这个例子是用server模式启动JConsole的,使用的是ParallelScavenge GC,它的年老代对应的收集器在这里:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202007/31/5e5bc7393b2abe379e9ca1eebfdeb183.png)
该收集器的总收集次数在此,这也就是full GC的次数:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202007/31/a5066bcf904a5ae453b02487fb543b8e.png)
于是只要知道我们用的JVM提供的GC MXBean的名字与分代的关系,就可以知道full GC的次数了。
Java代码写起来冗长,这帖就不用Java来写例子了,反正API是一样的,意思能表达清楚就OK。
用一个Groovy脚本简单演示一下适用于Oracle
(Sun) HotSpot与Oracle (BEA) JRockit的GC统计程序:
Groovy代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
import java.lang.management.ManagementFactory
printGCStats = {
def youngGenCollectorNames = [
// Oracle (Sun) HotSpot
// -XX:+UseSerialGC
'Copy',
// -XX:+UseParNewGC
'ParNew',
// -XX:+UseParallelGC
'PS Scavenge',
// Oracle (BEA) JRockit
// -XgcPrio:pausetime
'Garbage collection optimized for short pausetimes Young Collector',
// -XgcPrio:throughput
'Garbage collection optimized for throughput Young Collector',
// -XgcPrio:deterministic
'Garbage collection optimized for deterministic pausetimes Young Collector'
]
def oldGenCollectorNames = [
// Oracle (Sun) HotSpot
// -XX:+UseSerialGC
'MarkSweepCompact',
// -XX:+UseParallelGC and (-XX:+UseParallelOldGC or -XX:+UseParallelOldGCCompacting)
'PS MarkSweep',
// -XX:+UseConcMarkSweepGC
'ConcurrentMarkSweep',
// Oracle (BEA) JRockit
// -XgcPrio:pausetime
'Garbage collection optimized for short pausetimes Old Collector',
// -XgcPrio:throughput
'Garbage collection optimized for throughput Old Collector',
// -XgcPrio:deterministic
'Garbage collection optimized for deterministic pausetimes Old Collector'
]
R: {
ManagementFactory.garbageCollectorMXBeans.each {
def name = it.name
def count = it.collectionCount
def gcType;
switch (name) {
case youngGenCollectorNames:
gcType = 'Minor Collection'
break
case oldGenCollectorNames:
gcType = 'Major Collection'
break
default:
gcType = 'Unknown Collection Type'
break
}
println "$count <- $gcType: $name"
}
}
}
printGCStats()
执行可以看到类似这样的输出:
Command prompt代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
5 <- Minor Collection: Copy
0 <- Major Collection: MarkSweepCompact
↑这是用client模式的HotSpot执行得到的;
Command prompt代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
0 <- Minor Collection: Garbage collection optimized for throughput Young Collector
0 <- Major Collection: Garbage collection optimized for throughput Old Collector
↑这是用JRockit R28在32位Windows上的默认模式得到的。
通过上述方法,要包装起来方便以后使用的话也很简单,例如下面Groovy程序:
Groovy代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
import java.lang.management.ManagementFactory
class GCStats {
static final List<String> YoungGenCollectorNames = [
// Oracle (Sun) HotSpot
// -XX:+UseSerialGC
'Copy',
// -XX:+UseParNewGC
'ParNew',
// -XX:+UseParallelGC
'PS Scavenge',
// Oracle (BEA) JRockit
// -XgcPrio:pausetime
'Garbage collection optimized for short pausetimes Young Collector',
// -XgcPrio:throughput
'Garbage collection optimized for throughput Young Collector',
// -XgcPrio:deterministic
'Garbage collection optimized for deterministic pausetimes Young Collector'
]
static final List<String> OldGenCollectorNames = [
// Oracle (Sun) HotSpot
// -XX:+UseSerialGC
'MarkSweepCompact',
// -XX:+UseParallelGC and (-XX:+UseParallelOldGC or -XX:+UseParallelOldGCCompacting)
'PS MarkSweep',
// -XX:+UseConcMarkSweepGC
'ConcurrentMarkSweep',
// Oracle (BEA) JRockit
// -XgcPrio:pausetime
'Garbage collection optimized for short pausetimes Old Collector',
// -XgcPrio:throughput
'Garbage collection optimized for throughput Old Collector',
// -XgcPrio:deterministic
'Garbage collection optimized for deterministic pausetimes Old Collector'
]
static int getYoungGCCount() {
ManagementFactory.garbageCollectorMXBeans.inject(0) { youngGCCount, gc ->
if (YoungGenCollectorNames.contains(gc.name))
youngGCCount + gc.collectionCount
else
youngGCCount
}
}
static int getFullGCCount() {
ManagementFactory.garbageCollectorMXBeans.inject(0) { fullGCCount, gc ->
if (OldGenCollectorNames.contains(gc.name))
fullGCCount + gc.collectionCount
else
fullGCCount
}
}
}
用的时候:
Groovysh代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
D:\>\sdk\groovy-1.7.2\bin\groovysh
Groovy Shell (1.7.2, JVM: 1.6.0_20)
Type 'help' or '\h' for help.
--------------------------------------------------
groovy:000> GCStats.fullGCCount
===> 0
groovy:000> System.gc()
===> null
groovy:000> GCStats.fullGCCount
===> 1
groovy:000> System.gc()
===> null
groovy:000> System.gc()
===> null
groovy:000> GCStats.fullGCCount
===> 3
groovy:000> GCStats.youngGCCount
===> 9
groovy:000> GCStats.youngGCCount
===> 9
groovy:000> GCStats.youngGCCount
===> 9
groovy:000> System.gc()
===> null
groovy:000> GCStats.youngGCCount
===> 9
groovy:000> GCStats.fullGCCount
===> 4
groovy:000> quit
这是在Sun JDK 6 update 20上跑的。顺带一提,如果这是跑在JRockit上的话,那full GC的次数就不会增加——因为JRockit里System.gc()默认是触发young GC的;请不要因为Sun HotSpot的默认行为而认为System.gc()总是会触发full GC的。
Poonam Bajaj以前也写过一篇blog提到HotSpot VM里的GC MBean的名字的:
Collector names
for GarbageCollectorMXBean MXBean
关于JMX的MXBean的使用,也可以参考下面两篇文档:
Groovy and JMX
Monitoring the JVM Heap with
JRuby
GC次数:
引用
hi,问个问题,怎们在java中获取到full gc的次数呢?
我现在用jmx的那个得到了gc次数,不过不能细化出来full gc的次数
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
for (final GarbageCollectorMXBean garbageCollector
: ManagementFactory.getGarbageCollectorMXBeans()) {
gcCounts += garbageCollector.getCollectionCount();
}
你比如我现在是这样拿次数的
我回答说因为full GC概念只有在分代式GC的上下文中才存在,而JVM并不强制要求GC使用分代式实现,所以JMX提供的标准MXBean API里不提供“full
GC次数”这样的方法也正常。
既然“full GC”本来就是非常平台相关的概念,那就hack一点,用平台相关的代码来解决问题好了。这些GC的MXBean都是有名字的,而主流的JVM的GC名字相对稳定,非要通过JMX得到full GC次数的话,用名字来判断一下就好了。
举个例子来看看。通过JDK 6自带的JConsole工具来查看相关的MXBean的话,可以看到,
GC的MXBean在这个位置:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202007/31/bbd368f1878d0ca3f92ef718e4514000.png)
这个例子是用server模式启动JConsole的,使用的是ParallelScavenge GC,它的年老代对应的收集器在这里:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202007/31/5e5bc7393b2abe379e9ca1eebfdeb183.png)
该收集器的总收集次数在此,这也就是full GC的次数:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202007/31/a5066bcf904a5ae453b02487fb543b8e.png)
于是只要知道我们用的JVM提供的GC MXBean的名字与分代的关系,就可以知道full GC的次数了。
Java代码写起来冗长,这帖就不用Java来写例子了,反正API是一样的,意思能表达清楚就OK。
用一个Groovy脚本简单演示一下适用于Oracle
(Sun) HotSpot与Oracle (BEA) JRockit的GC统计程序:
Groovy代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
import java.lang.management.ManagementFactory
printGCStats = {
def youngGenCollectorNames = [
// Oracle (Sun) HotSpot
// -XX:+UseSerialGC
'Copy',
// -XX:+UseParNewGC
'ParNew',
// -XX:+UseParallelGC
'PS Scavenge',
// Oracle (BEA) JRockit
// -XgcPrio:pausetime
'Garbage collection optimized for short pausetimes Young Collector',
// -XgcPrio:throughput
'Garbage collection optimized for throughput Young Collector',
// -XgcPrio:deterministic
'Garbage collection optimized for deterministic pausetimes Young Collector'
]
def oldGenCollectorNames = [
// Oracle (Sun) HotSpot
// -XX:+UseSerialGC
'MarkSweepCompact',
// -XX:+UseParallelGC and (-XX:+UseParallelOldGC or -XX:+UseParallelOldGCCompacting)
'PS MarkSweep',
// -XX:+UseConcMarkSweepGC
'ConcurrentMarkSweep',
// Oracle (BEA) JRockit
// -XgcPrio:pausetime
'Garbage collection optimized for short pausetimes Old Collector',
// -XgcPrio:throughput
'Garbage collection optimized for throughput Old Collector',
// -XgcPrio:deterministic
'Garbage collection optimized for deterministic pausetimes Old Collector'
]
R: {
ManagementFactory.garbageCollectorMXBeans.each {
def name = it.name
def count = it.collectionCount
def gcType;
switch (name) {
case youngGenCollectorNames:
gcType = 'Minor Collection'
break
case oldGenCollectorNames:
gcType = 'Major Collection'
break
default:
gcType = 'Unknown Collection Type'
break
}
println "$count <- $gcType: $name"
}
}
}
printGCStats()
执行可以看到类似这样的输出:
Command prompt代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
5 <- Minor Collection: Copy
0 <- Major Collection: MarkSweepCompact
↑这是用client模式的HotSpot执行得到的;
Command prompt代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
0 <- Minor Collection: Garbage collection optimized for throughput Young Collector
0 <- Major Collection: Garbage collection optimized for throughput Old Collector
↑这是用JRockit R28在32位Windows上的默认模式得到的。
通过上述方法,要包装起来方便以后使用的话也很简单,例如下面Groovy程序:
Groovy代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
import java.lang.management.ManagementFactory
class GCStats {
static final List<String> YoungGenCollectorNames = [
// Oracle (Sun) HotSpot
// -XX:+UseSerialGC
'Copy',
// -XX:+UseParNewGC
'ParNew',
// -XX:+UseParallelGC
'PS Scavenge',
// Oracle (BEA) JRockit
// -XgcPrio:pausetime
'Garbage collection optimized for short pausetimes Young Collector',
// -XgcPrio:throughput
'Garbage collection optimized for throughput Young Collector',
// -XgcPrio:deterministic
'Garbage collection optimized for deterministic pausetimes Young Collector'
]
static final List<String> OldGenCollectorNames = [
// Oracle (Sun) HotSpot
// -XX:+UseSerialGC
'MarkSweepCompact',
// -XX:+UseParallelGC and (-XX:+UseParallelOldGC or -XX:+UseParallelOldGCCompacting)
'PS MarkSweep',
// -XX:+UseConcMarkSweepGC
'ConcurrentMarkSweep',
// Oracle (BEA) JRockit
// -XgcPrio:pausetime
'Garbage collection optimized for short pausetimes Old Collector',
// -XgcPrio:throughput
'Garbage collection optimized for throughput Old Collector',
// -XgcPrio:deterministic
'Garbage collection optimized for deterministic pausetimes Old Collector'
]
static int getYoungGCCount() {
ManagementFactory.garbageCollectorMXBeans.inject(0) { youngGCCount, gc ->
if (YoungGenCollectorNames.contains(gc.name))
youngGCCount + gc.collectionCount
else
youngGCCount
}
}
static int getFullGCCount() {
ManagementFactory.garbageCollectorMXBeans.inject(0) { fullGCCount, gc ->
if (OldGenCollectorNames.contains(gc.name))
fullGCCount + gc.collectionCount
else
fullGCCount
}
}
}
用的时候:
Groovysh代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201609/18c34b6f57d3b40bb521bca5357ac9cc.png)
D:\>\sdk\groovy-1.7.2\bin\groovysh
Groovy Shell (1.7.2, JVM: 1.6.0_20)
Type 'help' or '\h' for help.
--------------------------------------------------
groovy:000> GCStats.fullGCCount
===> 0
groovy:000> System.gc()
===> null
groovy:000> GCStats.fullGCCount
===> 1
groovy:000> System.gc()
===> null
groovy:000> System.gc()
===> null
groovy:000> GCStats.fullGCCount
===> 3
groovy:000> GCStats.youngGCCount
===> 9
groovy:000> GCStats.youngGCCount
===> 9
groovy:000> GCStats.youngGCCount
===> 9
groovy:000> System.gc()
===> null
groovy:000> GCStats.youngGCCount
===> 9
groovy:000> GCStats.fullGCCount
===> 4
groovy:000> quit
这是在Sun JDK 6 update 20上跑的。顺带一提,如果这是跑在JRockit上的话,那full GC的次数就不会增加——因为JRockit里System.gc()默认是触发young GC的;请不要因为Sun HotSpot的默认行为而认为System.gc()总是会触发full GC的。
Poonam Bajaj以前也写过一篇blog提到HotSpot VM里的GC MBean的名字的:
Collector names
for GarbageCollectorMXBean MXBean
关于JMX的MXBean的使用,也可以参考下面两篇文档:
Groovy and JMX
Monitoring the JVM Heap with
JRuby
相关文章推荐
- Spring整合Hibernate
- 浅谈Java设计模式(十四)模板方法模式(Template Method)
- eclipse安装spring tool suite插件
- JAVA Thread.setDaemon用法
- Struts2的执行流程
- Java基础之强引用,软引用,弱引用,虚引用
- svn 导入的 web项目怎么变成了java项目了
- 浅谈Java设计模式(十三)策略模式(strategy)
- java继承和组合
- spring.net 概念-控制反转(又名依赖注入)
- Spring 3.2.* MVC通过Ajax获取JSON数据报406错误
- JAVA中的反射机制
- Struts2的参数传递
- Action执行的方法
- 浅谈Java设计模式(十二)享元模式(Flyweight)
- Java守护线程与非守护线程
- Struts2的动态方法调用
- Java的Hibernate框架中的组合映射学习教程
- 深入理解JDK中的I/O
- Action的生命周期