code: package org.gridkit.jvmtool.gcflow;
  
  import java.io.IOException;
  import java.lang.management.GarbageCollectorMXBean;
  import java.lang.management.ManagementFactory;
  import java.lang.management.RuntimeMXBean;
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import javax.management.JMX;
  import javax.management.MBeanServerConnection;
  import javax.management.MalformedObjectNameException;
  import javax.management.ObjectName;
  
  class GcKnowledgeBase {
  
      enum PoolType {
  
          EDEN,
          SURVIVOR,
          TENURED,
          PERMANENT
  
      }
  
      private static GcTypeMatcher[] GC_CATALOG = {
          // HotSpot default
          eden("Copy", "Eden Space"),
          survivour("Copy", "Survivor Space"),
          tenured("MarkSweepCompact", "Tenured Gen"),
          permanent("MarkSweepCompact", "Perm Gen"),
          permanent("MarkSweepCompact", "Perm Gen [shared-ro]"),
          permanent("MarkSweepCompact", "Perm Gen [shared-rw]"),
  
          // HotSpot Parallel Scavenge and Parallel Old GC
          eden("PS Scavenge", "PS Eden Space"),
          survivour("PS Scavenge", "PS Survivor Space"),
          tenured("PS MarkSweep", "PS Old Gen"),
          permanent("PS MarkSweep", "PS Perm Gen"),
  
          // Concurrent Mark Sweep
          eden("ParNew", "Par Eden Space"),
          survivour("ParNew", "Par Survivor Space"),
          tenured("ConcurrentMarkSweep", "CMS Old Gen"),
          permanent("ConcurrentMarkSweep", "CMS Perm Gen"),
  
          // G1
          eden("G1 Young Generation", "G1 Eden"),
          survivour("G1 Young Generation", "G1 Survivor"),
          tenured("G1 Old Generation", "G1 Old Gen"),
          permanent("G1 Old Generation", "G1 Perm Gen"),
  
          // JRockit
          eden("JRockit", "Nursery"),
          // no separate survivor space
          tenured("JRockit", "Old Space"),
          permanent("JRockit", "Class Memory"),
      };
  
      public static ObjectName RUNTIME_MXBEAN = name(ManagementFactory.RUNTIME_MXBEAN_NAME);
  
      public static ObjectName COLLECTORS_PATTERN = name("java.lang:type=GarbageCollector,name=*");
  
      private static ObjectName name(String name) {
          try {
              return new ObjectName(name);
          } catch (MalformedObjectNameException e) {
              throw new RuntimeException(e);
          }
      }
  
  
      public static Collection<String> allCollectedPools(MBeanServerConnection conn) throws IOException {
  
          Set<String> pools = new LinkedHashSet<String>();
  
          for(ObjectName gcn: conn.queryNames(COLLECTORS_PATTERN, null)) {
              GarbageCollectorMXBean gc = JMX.newMXBeanProxy(conn, gcn, GarbageCollectorMXBean.class);
  
              for(String pool: gc.getMemoryPoolNames()) {
                  pools.add(pool);
              }
          }
          return pools;
      }
  
      public static Map<PoolType, Collection<String>> classifyMemoryPools(MBeanServerConnection conn) throws IOException {
  
          RuntimeMXBean rtmx = JMX.newMXBeanProxy(conn, RUNTIME_MXBEAN, RuntimeMXBean.class);
  
          boolean jrockit = rtmx.getVmName().toUpperCase().contains("JROCKIT");
          Map<PoolType, Collection<String>> map = new HashMap<GcKnowledgeBase.PoolType, Collection<String>>();
          for(ObjectName gcn: conn.queryNames(COLLECTORS_PATTERN, null)) {
              GarbageCollectorMXBean gc = JMX.newMXBeanProxy(conn, gcn, GarbageCollectorMXBean.class);
  
              String gcName = jrockit ? "JRockit" : gc.getName();
              for(String pool: gc.getMemoryPoolNames()) {
                  PoolType type = classify(gcName, pool);
                  if (type != null) {
                      add(map, type, pool);
                  }
              }
          }
          return map;
      }
  
      public static PoolType classify(String gcName, String pool) {
          for(GcTypeMatcher m: GC_CATALOG) {
              if (m.gcName.equals(gcName) && m.poolName.equals(pool)) {
                  return m.type;
              }
          }
          return null;
      }
  
      private static void add(Map<PoolType, Collection<String>> map, PoolType type, String name) {
          if (map.containsKey(type)) {
              List<String> names = new ArrayList<String>();
              names.addAll(map.get(type));
              names.add(name);
              map.put(type, names);
          }
          else {
              map.put(type, Collections.singleton(name));
          }
      }
  
      private static GcTypeMatcher eden(String algo, String poolName) {
          return new GcTypeMatcher(algo, poolName, PoolType.EDEN);
      }
  
      private static GcTypeMatcher survivour(String algo, String poolName) {
          return new GcTypeMatcher(algo, poolName, PoolType.SURVIVOR);
      }
  
      private static GcTypeMatcher tenured(String algo, String poolName) {
          return new GcTypeMatcher(algo, poolName, PoolType.TENURED);
      }
  
      private static GcTypeMatcher permanent(String algo, String poolName) {
          return new GcTypeMatcher(algo, poolName, PoolType.PERMANENT);
      }
  
      private static class GcTypeMatcher {
  
          String gcName;
          String poolName;
          PoolType type;
  
          public GcTypeMatcher(String gcName, String poolName, PoolType type) {
              this.gcName = gcName;
              this.poolName = poolName;
              this.type = type;
          }
      }
  }
  