|
|
@ -100,26 +100,38 @@ public class HeapDumpWebEndpoint {
|
|
|
|
if (this.heapDumper == null) {
|
|
|
|
if (this.heapDumper == null) {
|
|
|
|
this.heapDumper = createHeapDumper();
|
|
|
|
this.heapDumper = createHeapDumper();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
File file = createTempFile(live);
|
|
|
|
File file = createTempFile();
|
|
|
|
this.heapDumper.dumpHeap(file, live);
|
|
|
|
this.heapDumper.dumpHeap(file, live);
|
|
|
|
return new TemporaryFileSystemResource(file);
|
|
|
|
return new TemporaryFileSystemResource(file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private File createTempFile(boolean live) throws IOException {
|
|
|
|
private File createTempFile() throws IOException {
|
|
|
|
String date = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm").format(LocalDateTime.now());
|
|
|
|
String date = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm").format(LocalDateTime.now());
|
|
|
|
File file = File.createTempFile("heapdump" + date + (live ? "-live" : ""), ".hprof");
|
|
|
|
File file = File.createTempFile("heap-" + date, "." + determineDumpSuffix());
|
|
|
|
file.delete();
|
|
|
|
file.delete();
|
|
|
|
return file;
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private String determineDumpSuffix() {
|
|
|
|
|
|
|
|
if (this.heapDumper instanceof OpenJ9DiagnosticsMXBeanHeapDumper) {
|
|
|
|
|
|
|
|
return "phd";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return "hprof";
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Factory method used to create the {@link HeapDumper}.
|
|
|
|
* Factory method used to create the {@link HeapDumper}.
|
|
|
|
* @return the heap dumper to use
|
|
|
|
* @return the heap dumper to use
|
|
|
|
* @throws HeapDumperUnavailableException if the heap dumper cannot be created
|
|
|
|
* @throws HeapDumperUnavailableException if the heap dumper cannot be created
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
protected HeapDumper createHeapDumper() throws HeapDumperUnavailableException {
|
|
|
|
protected HeapDumper createHeapDumper() throws HeapDumperUnavailableException {
|
|
|
|
|
|
|
|
try {
|
|
|
|
return new HotSpotDiagnosticMXBeanHeapDumper();
|
|
|
|
return new HotSpotDiagnosticMXBeanHeapDumper();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (HeapDumperUnavailableException ex) {
|
|
|
|
|
|
|
|
return new OpenJ9DiagnosticsMXBeanHeapDumper();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Strategy interface used to dump the heap to a file.
|
|
|
|
* Strategy interface used to dump the heap to a file.
|
|
|
@ -140,8 +152,8 @@ public class HeapDumpWebEndpoint {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* {@link HeapDumper} that uses {@code com.sun.management.HotSpotDiagnosticMXBean}
|
|
|
|
* {@link HeapDumper} that uses {@code com.sun.management.HotSpotDiagnosticMXBean},
|
|
|
|
* available on Oracle and OpenJDK to dump the heap to a file.
|
|
|
|
* available on Oracle and OpenJDK, to dump the heap to a file.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|
protected static class HotSpotDiagnosticMXBeanHeapDumper implements HeapDumper {
|
|
|
|
protected static class HotSpotDiagnosticMXBeanHeapDumper implements HeapDumper {
|
|
|
|
|
|
|
|
|
|
|
@ -171,6 +183,38 @@ public class HeapDumpWebEndpoint {
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* {@link HeapDumper} that uses
|
|
|
|
|
|
|
|
* {@code openj9.lang.management.OpenJ9DiagnosticsMXBean}, available on OpenJ9, to
|
|
|
|
|
|
|
|
* dump the heap to a file.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private static final class OpenJ9DiagnosticsMXBeanHeapDumper implements HeapDumper {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Object diagnosticMXBean;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Method dumpHeapMethod;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
|
|
|
|
private OpenJ9DiagnosticsMXBeanHeapDumper() {
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
Class<?> mxBeanClass = ClassUtils.resolveClassName("openj9.lang.management.OpenJ9DiagnosticsMXBean",
|
|
|
|
|
|
|
|
null);
|
|
|
|
|
|
|
|
this.diagnosticMXBean = ManagementFactory.getPlatformMXBean((Class<PlatformManagedObject>) mxBeanClass);
|
|
|
|
|
|
|
|
this.dumpHeapMethod = ReflectionUtils.findMethod(mxBeanClass, "triggerDumpToFile", String.class,
|
|
|
|
|
|
|
|
String.class);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (Throwable ex) {
|
|
|
|
|
|
|
|
throw new HeapDumperUnavailableException("Unable to locate OpenJ9DiagnosticsMXBean", ex);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
|
|
public void dumpHeap(File file, boolean live) throws IOException, InterruptedException {
|
|
|
|
|
|
|
|
ReflectionUtils.invokeMethod(this.dumpHeapMethod, this.diagnosticMXBean, "heap", file.getAbsolutePath());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Exception to be thrown if the {@link HeapDumper} cannot be created.
|
|
|
|
* Exception to be thrown if the {@link HeapDumper} cannot be created.
|
|
|
|
*/
|
|
|
|
*/
|
|
|
|