通过Java/JMX得到full GC次数?

论坛 期权论坛 脚本     
匿名技术用户   2020-12-30 03:10   11   0
今天有个同事问如何能通过JMX获取到某个Java进程的full GC次数:
引用
hi,问个问题,怎们在java中获取到full gc的次数呢?
我现在用jmx的那个得到了gc次数,不过不能细化出来full gc的次数

Java代码 复制代码
  1. for (final GarbageCollectorMXBean garbageCollector
  2. : ManagementFactory.getGarbageCollectorMXBeans()) {
  3. gcCounts += garbageCollector.getCollectionCount();
  4. }
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代码 复制代码
  1. import java.lang.management.ManagementFactory
  2. printGCStats = {
  3. def youngGenCollectorNames = [
  4. // Oracle (Sun) HotSpot
  5. // -XX:+UseSerialGC
  6. 'Copy',
  7. // -XX:+UseParNewGC
  8. 'ParNew',
  9. // -XX:+UseParallelGC
  10. 'PS Scavenge',
  11. // Oracle (BEA) JRockit
  12. // -XgcPrio:pausetime
  13. 'Garbage collection optimized for short pausetimes Young Collector',
  14. // -XgcPrio:throughput
  15. 'Garbage collection optimized for throughput Young Collector',
  16. // -XgcPrio:deterministic
  17. 'Garbage collection optimized for deterministic pausetimes Young Collector'
  18. ]
  19. def oldGenCollectorNames = [
  20. // Oracle (Sun) HotSpot
  21. // -XX:+UseSerialGC
  22. 'MarkSweepCompact',
  23. // -XX:+UseParallelGC and (-XX:+UseParallelOldGC or -XX:+UseParallelOldGCCompacting)
  24. 'PS MarkSweep',
  25. // -XX:+UseConcMarkSweepGC
  26. 'ConcurrentMarkSweep',
  27. // Oracle (BEA) JRockit
  28. // -XgcPrio:pausetime
  29. 'Garbage collection optimized for short pausetimes Old Collector',
  30. // -XgcPrio:throughput
  31. 'Garbage collection optimized for throughput Old Collector',
  32. // -XgcPrio:deterministic
  33. 'Garbage collection optimized for deterministic pausetimes Old Collector'
  34. ]
  35. R: {
  36. ManagementFactory.garbageCollectorMXBeans.each {
  37. def name = it.name
  38. def count = it.collectionCount
  39. def gcType;
  40. switch (name) {
  41. case youngGenCollectorNames:
  42. gcType = 'Minor Collection'
  43. break
  44. case oldGenCollectorNames:
  45. gcType = 'Major Collection'
  46. break
  47. default:
  48. gcType = 'Unknown Collection Type'
  49. break
  50. }
  51. println "$count <- $gcType: $name"
  52. }
  53. }
  54. }
  55. printGCStats()
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代码 复制代码
  1. 5 <- Minor Collection: Copy
  2. 0 <- Major Collection: MarkSweepCompact
5 <- Minor Collection: Copy
0 <- Major Collection: MarkSweepCompact

↑这是用client模式的HotSpot执行得到的;
Command prompt代码 复制代码
  1. 0 <- Minor Collection: Garbage collection optimized for throughput Young Collector
  2. 0 <- Major Collection: Garbage collection optimized for throughput Old Collector
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代码 复制代码
  1. import java.lang.management.ManagementFactory
  2. class GCStats {
  3. static final List<String> YoungGenCollectorNames = [
  4. // Oracle (Sun) HotSpot
  5. // -XX:+UseSerialGC
  6. 'Copy',
  7. // -XX:+UseParNewGC
  8. 'ParNew',
  9. // -XX:+UseParallelGC
  10. 'PS Scavenge',
  11. // Oracle (BEA) JRockit
  12. // -XgcPrio:pausetime
  13. 'Garbage collection optimized for short pausetimes Young Collector',
  14. // -XgcPrio:throughput
  15. 'Garbage collection optimized for throughput Young Collector',
  16. // -XgcPrio:deterministic
  17. 'Garbage collection optimized for deterministic pausetimes Young Collector'
  18. ]
  19. static final List<String> OldGenCollectorNames = [
  20. // Oracle (Sun) HotSpot
  21. // -XX:+UseSerialGC
  22. 'MarkSweepCompact',
  23. // -XX:+UseParallelGC and (-XX:+UseParallelOldGC or -XX:+UseParallelOldGCCompacting)
  24. 'PS MarkSweep',
  25. // -XX:+UseConcMarkSweepGC
  26. 'ConcurrentMarkSweep',
  27. // Oracle (BEA) JRockit
  28. // -XgcPrio:pausetime
  29. 'Garbage collection optimized for short pausetimes Old Collector',
  30. // -XgcPrio:throughput
  31. 'Garbage collection optimized for throughput Old Collector',
  32. // -XgcPrio:deterministic
  33. 'Garbage collection optimized for deterministic pausetimes Old Collector'
  34. ]
  35. static int getYoungGCCount() {
  36. ManagementFactory.garbageCollectorMXBeans.inject(0) { youngGCCount, gc ->
  37. if (YoungGenCollectorNames.contains(gc.name))
  38. youngGCCount + gc.collectionCount
  39. else
  40. youngGCCount
  41. }
  42. }
  43. static int getFullGCCount() {
  44. ManagementFactory.garbageCollectorMXBeans.inject(0) { fullGCCount, gc ->
  45. if (OldGenCollectorNames.contains(gc.name))
  46. fullGCCount + gc.collectionCount
  47. else
  48. fullGCCount
  49. }
  50. }
  51. }
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代码 复制代码
  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()
  12. ===> null
  13. groovy:000> System.gc()
  14. ===> null
  15. groovy:000> GCStats.fullGCCount
  16. ===> 3
  17. groovy:000> GCStats.youngGCCount
  18. ===> 9
  19. groovy:000> GCStats.youngGCCount
  20. ===> 9
  21. groovy:000> GCStats.youngGCCount
  22. ===> 9
  23. groovy:000> System.gc()
  24. ===> null
  25. groovy:000> GCStats.youngGCCount
  26. ===> 9
  27. groovy:000> GCStats.fullGCCount
  28. ===> 4
  29. groovy:000> quit
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的。

关于JMX的MXBean的使用,也可以参考下面两篇文档:
Groovy and JMX
Monitoring the JVM Heap with JRuby
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:7942463
帖子:1588486
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP