用Java获取full GC的次数

本文介绍如何通过jstat工具和jvmstat API获取Java进程中Young GC与Full GC的次数,并提供了Groovy代码示例。

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

大家如果熟悉JDK 6的内建工具,或许已经知道可以通过 jstat 工具很轻松的从外部得知一个Java进程的GC统计信息,其中就包括了full GC的次数。 
假定我们相信jstat的数据是准确的,那么只要跟它从同一来源获取数据就可以保证我们拿到正确的full GC次数信息了。 
查看 OpenJDK  6中jstat的一个源文件, jdk/src/share/classes/sun/tools/jstat/resources/ jstat_options ,可以看到jstat -gcutil输出的YGC(young GC)与FGC(full GC)值分别是从下面两个定义而来的: 
Text代码   收藏代码
  1. column {  
  2.   header "^YGC^"    /* Young Generation Collections */  
  3.   data sun.gc.collector.0.invocations  
  4.   align right  
  5.   width 6  
  6.   format "0"  
  7. }  
  8. column {  
  9.   header "^FGC^"    /* Full Collections */  
  10.   data sun.gc.collector.1.invocations  
  11.   align right  
  12.   width 5  
  13.   scale raw  
  14.   format "0"  
  15. }  

也就是说,在Oracle (Sun) HotSpot上,通过 jvmstat API ,找到名字为  "sun.gc.collector.0.invocations"  与 "sun.gc.collector.1.invocations"  的 Monitor 对象,我们就可以拿到YGC与FGC对应的值了。别的JVM即便支持该API,Monitor的名字也可能会不同;在Oracle (BEA) JRockit R28上,两者对应的名字分别为 "jrockit.gc.latest.yc.number"  与  "jrockit.gc.latest.oc.number"  。 

在底层,HotSpot通过 perfData 接口来提供这些数据;注册数据的实现在 services 目录里。 

OpenJDK官网上也有一个相关文档: HotSpot Jvmstat Performance Counters  

提一下jvmstat文档上说的一个注意点: 
引用
The instrumented HotSpot JVM exports a set of instrumentation objects, or counters as they are typically called. The set of counters exported by a JVM is not static, as a JVM may create certain counters only when appropriate arguments are specified on the command line. Furthermore, different versions of a JVM may export very different sets of instrumentation.  The names of these counters and the data structures used to represent them are considered private, uncommitted interfaces to the HotSpot JVM. Users should not become dependent on any counter names, particularly those that start with prefixes other than "java.".

也就是说我们最好别依赖这些计数器的名字。不过反正这帖只是介绍些hack的办法而已,不管了   

下面用Groovy代码来演示一下。 
使用jvmstat API需要指定vmid,对多数系统上本地Java进程的VMID就是PID。这里正好用上 以前一帖 介绍的获取进程自己的PID的方式。 

Groovy代码   收藏代码
  1. import java.lang.management.ManagementFactory  
  2. import sun.jvmstat.monitor.*;  
  3.   
  4. class Runtimes {  
  5.   static int getOwnPid() {  
  6.     def name = ManagementFactory.runtimeMXBean.name  
  7.     name[0..<name.indexOf('@')] as int  
  8.   }  
  9. }  
  10.   
  11. class GCStats {  
  12.   // Oracle (Sun) HotSpot  
  13.   static final String YOUNG_GC_MONITOR_NAME = 'sun.gc.collector.0.invocations'  
  14.   static final String FULL_GC_MONITOR_NAME  = 'sun.gc.collector.1.invocations'  
  15.     
  16.   // Oracle (BEA) JRockit  
  17.   // static final String YOUNG_GC_MONITOR_NAME = 'jrockit.gc.latest.yc.number'  
  18.   // static final String FULL_GC_MONITOR_NAME  = 'jrockit.gc.latest.oc.number'  
  19.     
  20.   static final Monitor youngGCMonitor;  
  21.   static final Monitor fullGCMonitor;  
  22.     
  23.   static {  
  24.     def vmId     = new VmIdentifier(Runtimes.ownPid as String)  
  25.     def interval = 0  
  26.     def monitoredHost = MonitoredHost.getMonitoredHost(vmId)  
  27.     def monitoredVm = monitoredHost.getMonitoredVm(vmId, interval)  
  28.     youngGCMonitor = monitoredVm.findByName(YOUNG_GC_MONITOR_NAME)  
  29.     fullGCMonitor = monitoredVm.findByName(FULL_GC_MONITOR_NAME)  
  30.   }  
  31.     
  32.   static int getYoungGCCount() {  
  33.     youngGCMonitor.value  
  34.   }  
  35.     
  36.   static int getFullGCCount() {  
  37.     fullGCMonitor.value  
  38.   }  
  39. }  

可以看到,要获取young GC与full GC次数的读数很简单,找到合适的Monitor对象后,每次读一下value属性就好了。 
在Groovy shell里演示一下使用情况,在Sun JDK 6 update 20/Windows XP SP3上跑: 
Groovysh代码   收藏代码
  1. D:\>\sdk\groovy-1.7.2\bin\groovysh  
  2. Groovy Shell (1.7.2, JVM: 1.6.0_20)  
  3. Type 'help' or '\h' for help.  
  4. --------------------------------------------------  
  5. groovy:000> GCStats.fullGCCount  
  6. ===> 0  
  7. groovy:000> System.gc()  
  8. ===> null  
  9. groovy:000> GCStats.fullGCCount  
  10. ===> 1  
  11. groovy:000> System.gc(); System.gc(); System.gc()  
  12. ===> null  
  13. groovy:000> GCStats.fullGCCount  
  14. ===> 4  
  15. groovy:000> GCStats.youngGCCount  
  16. ===> 9  
  17. groovy:000> System.gc(); System.gc(); System.gc()  
  18. ===> null  
  19. groovy:000> GCStats.youngGCCount  
  20. ===> 9  
  21. groovy:000> GCStats.fullGCCount  
  22. ===> 7  
  23. groovy:000> quit  


这次也顺便演示一下在Oracle JRockit R28/Windows XP SP3上跑: 
Groovysh代码   收藏代码
  1. D:\>\sdk\groovy-1.7.2\bin\groovysh  
  2. Groovy Shell (1.7.2, JVM: 1.6.0_17)  
  3. Type 'help' or '\h' for help.  
  4. --------------------------------------------------  
  5. groovy:000> GCStats  
  6. ===> class GCStats  
  7. groovy:000> GCStats.youngGCCount  
  8. ===> 1  
  9. groovy:000> System.gc()  
  10. ===> null  
  11. groovy:000> GCStats.youngGCCount  
  12. ===> 2  
  13. groovy:000> System.gc(); System.gc(); System.gc()  
  14. ===> null  
  15. groovy:000> GCStats.youngGCCount  
  16. ===> 5  
  17. groovy:000> GCStats.fullGCCount  
  18. ===> 0  
  19. groovy:000> quit  

可以看到System.gc()引发的是young GC而不是full GC吧? ^_^
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值