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;
}
}
}