10

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.

Mickalot
  • 2,431
  • 3
  • 22
  • 23
  • 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. – Aleš Jun 08 '13 at 00:50
  • @AlesJ. OP stated that command line approach is not an option – Oleg Mikheev Jun 08 '13 at 00:53
  • @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). :-( – Mickalot Jun 08 '13 at 00:55
  • 1
    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. – Aleš Jun 08 '13 at 07:22

3 Answers3

7

You can get command line arguments by

ManagementFactory.getRuntimeMXBean().getInputArguments();
ZhongYu
  • 19,446
  • 5
  • 33
  • 61
  • 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. – FThompson Jun 08 '13 at 00:18
  • 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. – Mickalot Jun 08 '13 at 00:27
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.

Trevor Robinson
  • 15,694
  • 5
  • 73
  • 72
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.

Aleš
  • 8,896
  • 8
  • 62
  • 107
  • isn't HotSpotDiagnosticMXBean Oracle JVM specific? – Oleg Mikheev Jun 08 '13 at 00:50
  • @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. – Mickalot Jun 08 '13 at 01:01
  • @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: http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html . What JVM are you using that accepts it? – Mickalot Jun 08 '13 at 01:06
  • This is all Hotspot specific. Try `-XX:+UnlockDiagnosticVMOptions`, it should work with Hotspot 6 and 7. – Aleš Jun 08 '13 at 07:20
  • 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." – Mickalot Aug 23 '13 at 19:01