您的位置:首页 > 编程语言 > Java开发

通过Java/JMX得到full GC次数

2016-07-11 10:20 696 查看
今天有个同事问如何能通过JMX获取到某个Java进程的full
GC次数: 

引用

hi,问个问题,怎们在java中获取到full gc的次数呢? 

我现在用jmx的那个得到了gc次数,不过不能细化出来full gc的次数 

Java代码  


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在这个位置: 


 

这个例子是用server模式启动JConsole的,使用的是ParallelScavenge GC,它的年老代对应的收集器在这里: 


 

该收集器的总收集次数在此,这也就是full GC的次数: 


 

于是只要知道我们用的JVM提供的GC MXBean的名字与分代的关系,就可以知道full GC的次数了。 
Java代码写起来冗长,这帖就不用Java来写例子了,反正API是一样的,意思能表达清楚就OK。 
用一个Groovy脚本简单演示一下适用于Oracle
(Sun) HotSpot与Oracle (BEA) JRockit的GC统计程序: 

Groovy代码  


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代码  


5 <- Minor Collection: Copy  

0 <- Major Collection: MarkSweepCompact  

↑这是用client模式的HotSpot执行得到的; 

Command prompt代码  


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代码  


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代码  


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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: