Within a running JVM, how to programmatically determine the jvm options used at startup?
Asked Answered
L

3

11

Background: I'm doing some performance testing on a Java application that gets launched through several layers of indirection, such that I'm not entirely sure that the application is getting launched with the flags that I think it is. I'd like my application to include a sanity check (before it begins its performance test) and include in the results (after the test) information about how the JVM was tuned, such as:

  • Which garbage collector was used?
  • Was/is it actively doing cpu profiling?
  • Was/is it logging gc activity?
  • Was/is it in -Xint or -Xmixed mode?
  • Was/is -XX:ParallelGCThreads set -- if so, to what, and if not, what's the default for this build?
  • Was/is -XX:UseCompressedOops on or off?
  • etc.

Is there any way for Java code to (within a running JVM) query the actual options used for its containing JVM? (Assume that I can't see the command line that launched me, so I can't re-parse those flags.)

If there isn't a general-purpose way to determine this, answers that are specific to a particular JVM implementation are also welcome.

UPDATE:

It's important for the solution to be able to know what the default values are for any value that isn't explicitly supplied on the command-line. Otherwise, it's going to involve a lot of (error-prone) legwork to look up what the default value is for a given combination JVM/platform/version/architecture. I'm testing across a wide variety of JVMs, so I don't want to have to manually figure out what the default setting is for each parameter in each jvm release.

Lucid answered 7/6, 2013 at 23:58 Comment(4)
You could list the JVM process started by PID with ps -ef and there you can see all the input argument of that process. That should work for any JVM type.Wilscam
@AlesJ. OP stated that command line approach is not an optionHagi
@AlesJ. -- that would only give me explicitly set values, so I wouldn't get any information about the JVM's implicit defaults (see update edit to question). :-(Lucid
I see, too bad, this would have worked. I think there is no vendor-independent solution, for each VM you will need a specific approach. The default values for unspecified arguments are usually easy to find in the documentation.Wilscam
A
2

You could use a JMX client (like VisualVM) and then call getVMOption(String name), see HotSpotDiagnosticMXBean.

Or, if you could pass in at least one set of flags to enable JVM logging, it should be --XX:+LogVMOutput -XX:LogFile=jvm.log and then parse the output of the log from your app. The log contains all the flags/parameters used to startup the JVM.

Another option is to list the JVM process started by PID with ps -ef and there you can see all the input argument of that process. That should work for any JVM type.

Anaximander answered 8/6, 2013 at 0:21 Comment(5)
isn't HotSpotDiagnosticMXBean Oracle JVM specific?Hagi
@OlegMikheev - Although it's not ideal, I'd settle for any JVM-specific solutions (most of the users will likely be on Hotspot JVMs). But HotSpotDiagnosticMXBean looks like the wrong bean anyway...it tells me what diagnostics are in place (like what it should log when doing a GC) rather than how the VM is tuned.Lucid
@AlesJ. -- I tried a few Sun/Oracle J2SE jdks (mostly 1.6/1.7 32/64-bit on Linux), and none seem to recognize -XX:+LogVMOutput. I also don't see it here: oracle.com/technetwork/java/javase/tech/… . What JVM are you using that accepts it?Lucid
This is all Hotspot specific. Try -XX:+UnlockDiagnosticVMOptions, it should work with Hotspot 6 and 7.Wilscam
I'm selecting this as the "accepted" answer because I don't see a way to accept @AlesJ. comment in the question, which is "there is no vendor-independent solution, for each VM you will need a specific approach." Sadly, the answer to the question "How do I..." is "You don't."Lucid
S
8

You can get command line arguments by

ManagementFactory.getRuntimeMXBean().getInputArguments();
Samoyedic answered 8/6, 2013 at 0:7 Comment(2)
This was my first thought as well, but can it be used to determine specifics such as which garbage collector was used, if it is actively cpu profiling, and so forth? I believe you should elaborate in your answer.Burkhart
I totally appreciate this (and this was the first thing I tried), but the reason why this isn't what I'm looking for is because if the JVM option is unspecified, it's set to whatever the JVM's default is, and it isn't present in this list (which only contains explicitly-specified arguments). So it doesn't answer the question "What's the default for this build?" I'm testing on a lot of different machines, each of which may have a slightly different build with slightly different defaults.Lucid
L
5

The following Java 7 code will list all of the JVM options returned by -XX:+PrintFlagsFinal. It attempts to use reflection to access the package-protected Flag helper class (available since Java 6), and falls back to HotSpotDiagnosticMXBean.getDiagnosticOptions() if that doesn't work.

// load the diagnostic bean first to avoid UnsatisfiedLinkError
final HotSpotDiagnosticMXBean hsdiag = ManagementFactory
        .getPlatformMXBean(HotSpotDiagnosticMXBean.class);
List<VMOption> options;
try {
    final Class<?> flagClass = Class.forName("sun.management.Flag");
    final Method getAllFlagsMethod = flagClass.getDeclaredMethod("getAllFlags");
    final Method getVMOptionMethod = flagClass.getDeclaredMethod("getVMOption");
    getAllFlagsMethod.setAccessible(true);
    getVMOptionMethod.setAccessible(true);
    final Object result = getAllFlagsMethod.invoke(null);
    final List<?> flags = (List<?>) result;
    options = new ArrayList<VMOption>(flags.size());
    for (final Object flag : flags) {
        options.add((VMOption) getVMOptionMethod.invoke(flag));
    }
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
        | InvocationTargetException | ClassCastException e) {
    if (hsdiag != null) {
        // only includes writable external flags
        options = hsdiag.getDiagnosticOptions();
    } else {
        options = Collections.emptyList();
    }
}
final Map<String, VMOption> optionMap = new TreeMap<>();
for (final VMOption option : options) {
    optionMap.put(option.getName(), option);
}
for (final VMOption option : optionMap.values()) {
    System.out.println(option.getName() + " = " + option.getValue() + " (" +
            option.getOrigin() + ", " +
            (option.isWriteable() ? "read-write" : "read-only") + ")");
}
System.out.println(options.size() + " options found");

With 7u71, I get 663 options, or with -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions, 779.

Lavolta answered 24/3, 2015 at 2:23 Comment(0)
A
2

You could use a JMX client (like VisualVM) and then call getVMOption(String name), see HotSpotDiagnosticMXBean.

Or, if you could pass in at least one set of flags to enable JVM logging, it should be --XX:+LogVMOutput -XX:LogFile=jvm.log and then parse the output of the log from your app. The log contains all the flags/parameters used to startup the JVM.

Another option is to list the JVM process started by PID with ps -ef and there you can see all the input argument of that process. That should work for any JVM type.

Anaximander answered 8/6, 2013 at 0:21 Comment(5)
isn't HotSpotDiagnosticMXBean Oracle JVM specific?Hagi
@OlegMikheev - Although it's not ideal, I'd settle for any JVM-specific solutions (most of the users will likely be on Hotspot JVMs). But HotSpotDiagnosticMXBean looks like the wrong bean anyway...it tells me what diagnostics are in place (like what it should log when doing a GC) rather than how the VM is tuned.Lucid
@AlesJ. -- I tried a few Sun/Oracle J2SE jdks (mostly 1.6/1.7 32/64-bit on Linux), and none seem to recognize -XX:+LogVMOutput. I also don't see it here: oracle.com/technetwork/java/javase/tech/… . What JVM are you using that accepts it?Lucid
This is all Hotspot specific. Try -XX:+UnlockDiagnosticVMOptions, it should work with Hotspot 6 and 7.Wilscam
I'm selecting this as the "accepted" answer because I don't see a way to accept @AlesJ. comment in the question, which is "there is no vendor-independent solution, for each VM you will need a specific approach." Sadly, the answer to the question "How do I..." is "You don't."Lucid

© 2022 - 2024 — McMap. All rights reserved.