Programatically Dump Java Heap
Lately I have been tracking down memory leaks in OpenEJB using Your Kit. For some reason Your Kit throws verifier exceptions on my Mac when attempting to monitor my application. At first I tried switched to JProbe, but it simply reports incorrect heap view. Then Kevan suggested that I use -XX:+HeapDumpOnOutOfMemoryError to get the VM to dump heap when the OutOfMemoryError occurs, and use Your Kit to perform a post-mortem which worked to find the major leaks.
Now, I'm trying to release JCA connections when they are GCed, and in this case I'm not getting an OutOfMemoryError but a ResourceException which means I don't get a heap dump. Turning to Google again, I found this blog by A. Sundararajan on how to programatically dump the Java heap. I rewrote the code to use reflection to avoid a dependency on the Sun class and changed it to never throw an exception. Simply pop this in your code, and then open the HPROF heap with Your Kit.
Alternatively, if you just want heap information without adding code, you can use jconsole to execute the dumpHeap method, or "jmap -dump:file=FILENAME PID" to get dump. Of course this heap dump won't be from the exact point where your connection pool ran out of connections.
Now, I'm trying to release JCA connections when they are GCed, and in this case I'm not getting an OutOfMemoryError but a ResourceException which means I don't get a heap dump. Turning to Google again, I found this blog by A. Sundararajan on how to programatically dump the Java heap. I rewrote the code to use reflection to avoid a dependency on the Sun class and changed it to never throw an exception. Simply pop this in your code, and then open the HPROF heap with Your Kit.
/**
* Dumps the java heap to the specified file in hprof format.
* This method will not overwrite the dump file, so make sure it doesn't already exist.
* @param fileName the dump file name which must not already exist.
*/
public static void dumpHeap(String fileName) {
Class> clazz;
try {
clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean");
} catch (ClassNotFoundException e) {
System.out.println("ERROR: dumpHeap only works on a Sun Java 1.6+ VM containing " +
"the class com.sun.management.HotSpotDiagnosticMXBean");
return;
}
// use JMX to find hot spot mbean
Object hotspotMBean = null;
try {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
hotspotMBean = ManagementFactory.newPlatformMXBeanProxy(server,
"com.sun.management:type=HotSpotDiagnostic",
clazz);
} catch (Throwable e) {
System.out.print("ERROR: dumpHeap was unable to obtain the HotSpotDiagnosticMXBean: ");
e.printStackTrace();
}
// invoke the dumpHeap method
try {
Method method = hotspotMBean.getClass().getMethod("dumpHeap", String.class);
method.invoke(hotspotMBean, fileName);
} catch (InvocationTargetException e) {
Throwable t = e.getCause() != null ? e.getCause() : e;
System.out.print("ERROR: dumpHeap threw an exception: ");
t.printStackTrace();
} catch (Throwable e) {
System.out.print("ERROR: dumpHeap threw an exception: ");
e.printStackTrace();
}
}
Alternatively, if you just want heap information without adding code, you can use jconsole to execute the dumpHeap method, or "jmap -dump:file=FILENAME PID" to get dump. Of course this heap dump won't be from the exact point where your connection pool ran out of connections.
