Skip to main content

How much does it cost to monitor an app with jconsole?

Posted by emcmanus on July 21, 2006 at 8:39 AM PDT

Recently I've seen several people ask what the cost of enabling
JMX monitoring on an application is. If I run with
-Dcom.sun.management.jmxremote and connect
jconsole, how much will that affect the performance of my app?
Here are the results of some highly unscientific
experiments.

Here's the quick answer for people who look at the answers in
the back of the book. Running with
-Dcom.sun.management.jmxremote has no appreciable
impact. Connecting jconsole has an impact of 3--4%.

The answer to this question is likely to depend very much on
the nature of the app and what else is going on in the machine
where it is running. My measurements here are on a toy
application which computes digits of the mathematical constant
href="http://en.wikipedia.org/wiki/E_%28mathematical_constant%29">e
using href="http://download.java.net/jdk6/doc/api/java/math/BigInteger.html">BigInteger
arithmetic. This isn't intended to be an illustration of
appropriate mathematical techniques. It's just a simple way to
create an app that does a lot of computation and a lot of
allocation of large short-lived objects. So my measurements
here are likely to be interesting for apps like that, and
probably not wildly irrelevant for other sorts of apps.

Here for reference is the method that the app spends most of
its time in:

    private static void computeE(int digits) {
        BigInteger one = BigInteger.TEN.pow(digits);
        BigInteger e = BigInteger.ZERO;
        BigInteger invfact = one;
        BigInteger n = BigInteger.ONE;
        while (invfact.compareTo(BigInteger.ZERO) > 0) {
            e = e.add(invfact);
            invfact = invfact.divide(n);
            n = n.add(BigInteger.ONE);
        }
        System.out.println(e);
    }

Note by the way that the last few digits computed by this
method are inaccurate due to truncation of the division
results.

I ran this method with the digits parameter equal
to 30000 on an elderly SPARC machine. I was logged in to the
machine in an X Windows session too, so there was some
background activity. I ran each measurement two or three times
for each configuration and took the smallest time. (I did say
this was unscientific. What are these repeatable test
conditions
and standard deviations of which you
speak?)

I created one thread per CPU to make sure that the machine was
CPU-bound. Otherwise we might see zero overhead for enabling
monitoring because it might be using an otherwise-idle CPU.

Startup time is slightly greater when you enable
monitoring because it needs to do some extra work such as
creating an RMI connector. I assumed that the figure of
interest, though, is the cost while the app is running. So I
measured the time between the creation of the
computeE threads and their completion.

I used two Java platforms for the measurements: Sun's JDK 1.5.0_07
and a Mustang snapshot (1.6.0-rc-b92). The time for the
computation was 37% better on Mustang, presumably because of
improvements to the href="http://en.wikipedia.org/wiki/JIT_compiler">JIT
compiler and/or heap management. Also the time is better
still if you run with -server. But what we're
interested is the relative difference between monitoring and
not monitoring.

The first measurement was of the application running without
any special command-line parameters. So monitoring was not
enabled. This is the baseline for the other measurements.

Tiger Mustang
28.3 18.0

Then I ran the application with
-Dcom.sun.management.jmxremote, which has two
effects:

  • It creates the href="http://download.java.net/jdk6/doc/api/java/lang/management/ManagementFactory.html#getPlatformMBeanServer()">Platform
    MBean Server
    and populates it with the standard set of
    MBeans containing the JVM's instrumentation.

  • It creates and starts an href="http://download.java.net/jdk6/doc/api/javax/management/remote/rmi/RMIConnectorServer.html">RMI
    Connector Server and puts its address where jconsole can
    find it.

So with this option we could connect jconsole from the local
machine. But I didn't connect jconsole for this measurement.
The effect on performance was less than 1% in this case, and in
fact any observed difference was less than the margin of error.
So there was no significant difference in the time to do
the computation. In other words, so long as you don't connect
jconsole, enabling monitoring should have no effect on your
app's performance.

I got the same result when I ran with

-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.remote.ssl=false


so allowing jconsole to connect remotely but without security
also has no effect on performance. Note that we strongly
discourage
running apps this way in production
environments.

Running with

-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.password.file=jmxremote.password


(meaning there is security including the creation of an SSL
socket) also has an impact of less than 1%.

Then I ran the insecure options again but this time connected
Tiger's jconsole from another machine. Here are the figures I
got:

Tiger Mustang
29.85 (+5.5%) 19.1 (+6.1%)

So here there's a fairly big impact. Some of this is due to
jconsole polling the various JVM MBeans so it can graph the
changes in various values like heap size and number of threads
over time. There is no way to stop jconsole from doing that,
even if you're not interested in that information, but what you
can do is change the polling interval. If you change the
interval from the default 4 seconds to 1000 seconds, say, then
you won't see much impact from polling. (The interval also
applies to the graphing of your own attributes, though, so if
you want that then you'll have to pay for the JVM polling.)

Running Tiger's jconsole with -interval=1000
changes the figures to this:

Tiger Mustang
29.28 (+3.5%) 18.7 (+3.9%)

Jconsole isn't polling, but there's still some overhead,
presumably due to background activity from RMI and/or to increased
memory usage because of the open connection.

Mustang's jconsole, besides being generally nicer, has an
optimization that means it obtains the various JVM attributes much
more efficiently, so the polling impact is less. Even if you
can't migrate your apps to Mustang right now, you might want to
download the Mustang JDK just so you can run its jconsole!

Here are the figures running the app with the insecure options
and connecting with Mustang's jconsole from another machine:

Tiger Mustang
29.6 (+4.5%) 18.8 (+4.4%)

So you get better behaviour from jconsole by default here. And
of course you can still use the -interval=1000 trick,
to get this:

Tiger Mustang
29.2 (+3.2%) 18.7 (+3.9%)

Finally, I tried a few configurations with security enabled
(

-Dcom.sun.management.jmxremote.ssl=true
      -Dcom.sun.management.jmxremote.authenticate=true
, which
are the default settings) and did not see any signficant
difference. Even with jconsole polling every four seconds,
there was no observable extra overhead due to SSL.

Reminder

These results are not conclusive! They're merely indicative of
one set of measurements on one type of app. The impact could be
much greater if the addition of the JMX connection pushed the app
into a different mode of operation. For example, the additional
memory usage could be enough to change the behaviour of the
garbage collector significantly and probably negatively. But you
would have to be operating fairly close to the edge of such a
possible change for that to happen, meaning it could happen even
without the JMX connection if for example the app needed to handle a
few more objects.

Related Topics >>