javaspringjvmgraalvmgraalvm-native-image

Why can't I set HeapDumpOnOutOfMemoryError on GraalVM native image?


I want to auto dump when out of memory happen using this code

HotSpotDiagnosticMXBean bean = ManagementFactory.newPlatformMXBeanProxy(
        ManagementFactory.getPlatformMBeanServer(),
        "com.sun.management:type=HotSpotDiagnostic",
        HotSpotDiagnosticMXBean.class);
bean.setVMOption("HeapDumpOnOutOfMemoryError", "true");
bean.setVMOption("HeapDumpPath", fileName);

If I compile it using

mvn clean package

it works, but if I compile it using

mvn clean -Pnative native:compile 

The bean (HotSpotDiagnosticMXBean) is null, why is it null?


Solution

  • According to the javadoc for ManagementFactory.newPlatformMXBeanProxy, it will return null if it doesn't know about an MXBean interface with the name given by the second argument.

    I think we can assume that that is what is happening here because GraalVM is different.


    So how do you get a heap dump for an OOME on GraalVM?

    Well according to the GraalVM documentation you can use -XX:+HeapDumpOnOutOfMemoryError and related JVM options on the command line just like you can with an Oracle / OpenJDK HotSpot JVM. But this is only for GraalVM Java 21 and later; see https://github.com/oracle/graal/issues/4641.

    Alternatively, the GraalVM documentation also explains how an application can generate a heap dump programmatically. This is the gist of the example code that the documentation provides:

     private static void createHeapDump() {
         try {
             File file = File.createTempFile("SVMHeapDumpAPI-", ".hprof");
             VMRuntime.dumpHeap(file.getAbsolutePath(), false);
             System.out.println("  Heap dump created " +
                                file.getAbsolutePath() + 
                                ", size: " + file.length());
         } catch (UnsupportedOperationException unsupported) {
             System.err.println("Heap dump creation failed: " +
                                unsupported.getMessage());
         } catch (IOException ioe) {
             System.err.println("IO went wrong: " + ioe.getMessage());
         }
     }
    

    Caveat: I am merely quoting the documentation. I haven't tried any of this.