Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8280131

jcmd reports "Module jdk.jfr not found." when "jdk.management.jfr" is missing

XMLWordPrintable

    • jfr
    • b21
    • generic
    • generic

        ADDITIONAL SYSTEM INFORMATION :
        openjdk version "17.0.1" 2021-10-19
        OpenJDK Runtime Environment (build 17.0.1+12-39)
        OpenJDK 64-Bit Server VM (build 17.0.1+12-39, mixed mode, sharing)

        openjdk version "18-ea" 2022-03-15
        OpenJDK Runtime Environment (build 18-ea+25-1670)
        OpenJDK 64-Bit Server VM (build 18-ea+25-1670, mixed mode, sharing)

        A DESCRIPTION OF THE PROBLEM :
        Using jcmd to access Java Flight Recorder on a process running a jlink:ed runtime containing module "jdk.jfr", but missing module "jdk.management.jfr",
        jcmd reports "Module jdk.jfr not found."

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        The attached Java 17 source code first creates a module and two runtimes (one with and one without "jdk.management.jfr"),
        then launches the module with the two runtimes,
        then runs "jcmd <pid> JFR.check" and prints the output.

        java JcmdMissingModule.java

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        "Module jdk.management.jfr not found."
        ACTUAL -
        "Module jdk.jfr not found."

        ---------- BEGIN SOURCE ----------
        import java.io.ByteArrayOutputStream;
        import java.io.File;
        import java.io.InputStream;
        import java.nio.file.Files;
        import java.nio.file.Path;
        import java.util.Collections;
        import java.util.spi.ToolProvider;

        /**
         * jcmd prints message "Module jdk.jfr not found.",
         * when using slimmed jlink:ed runtime,
         * containing module "jdk.jfr".
         *
         * Adding "jdk.management.jfr" to the jlink:ed runtime,
         * makes jcmd happy.
         *
         * This java program creates source code of a module which just sleeps,
         * compiles that,
         * makes two jlink:ed runtimes (one without and one with module "jdk.management.jfr"),
         * launches the sleeping module with the both runtimes,
         * and invokes "jcmd <pid> JFR.check" on theses processes,
         * and prints their output.
         */
        class JcmdMissingModule {
            static ToolProvider javac = ToolProvider.findFirst("javac").orElseThrow(() -> new RuntimeException("No javac"));
            static ToolProvider jlink = ToolProvider.findFirst("jlink").orElseThrow(() -> new RuntimeException("No jlink"));
                                                                                                                                       
            static String module = "sleep";
            static String moduleInfo = "module %s {}".formatted(module);
            static String Main = """
                package example;
                class Main {
                    public static void main(String[] args) throws InterruptedException {
                        Thread.sleep(Long.MAX_VALUE);
                    }
                }
                """;
                                                                                                                                       
            public static void main(String[] args) throws Exception {
                Path out = Path.of("out");
                Path src = out.resolve("src");
                Path classes = out.resolve("classes");
                                                                       
                del(out);
                                                                                                                                       
                Files.createDirectories(src.resolve(module).resolve("example"));
                Files.write(src.resolve(module).resolve("module-info.java"), moduleInfo.getBytes());
                Files.write(src.resolve(module).resolve("example").resolve("Main.java"), Main.getBytes());
                                                                       
                // Compile module
                javac.run(System.out, System.err,
                        "--module-source-path", src.toString(),
                        "--module", module,
                        "-d", classes.toString());
                                                                       
                Path javaHome = Path.of(System.getProperty("java.home"));
                Path jmods = javaHome.resolve("jmods");
                Path jcmd = javaHome.resolve("bin").resolve("jcmd");
                                                                       
                String reproducerModules = String.join(",", module, "jdk.jfr", "jdk.management");
                String workaroundModules = String.join(",", module, "jdk.jfr", "jdk.management", "jdk.management.jfr");
                                                                                                                                       
                String modulePath = String.join(File.pathSeparator, jmods.toString(), classes.toString());
                String reproducer = out.resolve("reproducer").toString();
                String workaround = out.resolve("workaround").toString();
                                                                       
                // Create runtimes with limited set of modules
                jlink(reproducerModules, modulePath, reproducer);
                jlink(workaroundModules, modulePath, workaround);
                                                                       
                String reproducerJava = Path.of(reproducer, "bin", "java").toString();
                String workaroundJava = Path.of(workaround, "bin", "java").toString();
                                                                       
                String moduleWithMain = module + "/example.Main";
                                                                       
                // Start processes which just sleep
                long reproducerPid = run(reproducerJava, "--module", moduleWithMain).pid();
                long workaroundPid = run(workaroundJava, "--module", moduleWithMain).pid();

                // Run JFR.check on the processes
                String reproducerJcmd = runAndReadOutput(jcmd.toString(), String.valueOf(reproducerPid), "JFR.check");
                String workaroundJcmd = runAndReadOutput(jcmd.toString(), String.valueOf(workaroundPid), "JFR.check");
                                                                       
                // List modules
                String reproducerListModules = runAndReadOutput(reproducerJava, "--list-modules");
                String workaroundListModules = runAndReadOutput(workaroundJava, "--list-modules");
                                                                       
                System.out.println("""
                    jcmd:
                    %s
                    --list-modules:
                    %s
                                                                       
                    jcmd:
                    %s
                    --list-modules:
                    %s
                    """.formatted(reproducerJcmd, reproducerListModules, workaroundJcmd, workaroundListModules));
           }
                                                                                                                                       
            static Process run(String... cmd) throws Exception {
                Process process = new ProcessBuilder(cmd)
                    .redirectErrorStream(true)
                    .start();
                Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { process.destroy(); } } );
                return process;
            }
                                                                       
            static String runAndReadOutput(String... cmd) throws Exception {
                Process process = run(cmd);
                process.waitFor();
                String output = readOutput(process.getInputStream());
                return output;
            }
                                                                       
            static String readOutput(InputStream is) throws Exception {
                var baos = new ByteArrayOutputStream();
                is.transferTo(baos);
                return baos.toString();
            }
                                                                       
            static void jlink(String modules, String modulePath, String output) {
                jlink.run(System.out, System.err,
                        "--add-modules", modules,
                        "--module-path", modulePath,
                        "--output", output
                        );
            }
                                                                       
            static void del(Path dir) {
                if (dir.toFile().exists()) {
                    try (var files = Files.walk(dir)) {
                        files.sorted(Collections.reverseOrder()).map(Path::toFile).forEach(f -> f.delete());
                    } catch (Exception e) {}
                }
            }
        }
        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        Adding "jdk.management.jfr" to the jlink:ed runtime

        FREQUENCY : always


              egahlin Erik Gahlin
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              9 Start watching this issue

                Created:
                Updated:
                Resolved: