238

How to activate JMX on a JVM for access with jconsole?

Mauli
  • 15,951
  • 26
  • 80
  • 112
  • 32
    it is allowd, and actually it is only a reminder for me, because I always forget where to copy the parameters from and now I know where I find it :-) – Mauli May 15 '09 at 14:56
  • 20
    Stack Exchange has always explicitly encouraged users to answer their own questions, see here: http://stackoverflow.com/help/self-answer – Tim Büthe Jun 11 '14 at 14:31
  • 11
    More than once I have searched SO for something and found a question answered... by myself. And one of those was asked by me as well. This is why it is good to put your own answers in. Also, think of all the other people that may have encountered your problem, if you answer your question you will be helping them too. – Mike Miller Sep 09 '14 at 18:43
  • @Mauren: Can you provide a reference to your closed question you answered yourself? It might be worth discussing on Meta. – kevinarpe Nov 15 '15 at 12:25
  • @kevinarpe I'm sorry. This has been a long time ago and I'm no longer able to provide you with the link and content. – Mauren Dec 03 '15 at 16:32
  • 2
    Updated doc for Java 8 is [here](https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html) – Andrew Johnston Jul 28 '15 at 20:40
  • Question should mention you may have the exact same problem when jvisualvm tells you "Failed to create JMX connection to target application" when trying to start CPU sampling. – numéro6 Jun 19 '17 at 09:53

12 Answers12

306

The relevant documentation can be found here:

http://java.sun.com/javase/6/docs/technotes/guides/management/agent.html

Start your program with following parameters:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9010
-Dcom.sun.management.jmxremote.rmi.port=9010
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

For instance like this:

java -Dcom.sun.management.jmxremote \
  -Dcom.sun.management.jmxremote.port=9010 \
  -Dcom.sun.management.jmxremote.local.only=false \
  -Dcom.sun.management.jmxremote.authenticate=false \
  -Dcom.sun.management.jmxremote.ssl=false \
  -jar Notepad.jar

-Dcom.sun.management.jmxremote.local.only=false is not necessarily required but without it, it doesn't work on Ubuntu. The error would be something like this:

01 Oct 2008 2:16:22 PM sun.rmi.transport. customer .TCPTransport$AcceptLoop executeAcceptLoop
WARNING: RMI TCP Accept-0: accept loop for ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=37278] throws
java.io.IOException: The server sockets created using the LocalRMIServerSocketFactory only accept connections from clients running on the host where the RMI remote objects have been exported.
    at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(LocalRMIServerSocketFactory.java:89)
    at sun.rmi.transport. customer .TCPTransport$AcceptLoop.executeAcceptLoop(TCPTransport.java:387)
    at sun.rmi.transport. customer .TCPTransport$AcceptLoop.run(TCPTransport.java:359)
    at java.lang.Thread.run(Thread.java:636)

see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6754672

Also be careful with -Dcom.sun.management.jmxremote.authenticate=false which makes access available for anyone, but if you only use it to track the JVM on your local machine it doesn't matter.

Update:

In some cases I was not able to reach the server. This was then fixed if I set this parameter as well: -Djava.rmi.server.hostname=127.0.0.1

FUD
  • 4,873
  • 6
  • 36
  • 59
Mauli
  • 15,951
  • 26
  • 80
  • 112
  • 10
    The -Dcom.sun.management.jmxremote.local.only=false is needed on Centos now as well – LenW Nov 01 '12 at 07:54
  • 1
    Nit pick: It's weird to me that `com.sun.management.jmxremote` has the default value as `true`. (Thank you Sun!) To be super clear, especially to those less familiar with JMX nobs, I use: `com.sun.management.jmxremote=true` Ref: http://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html – kevinarpe Nov 15 '15 at 12:28
  • 2
    "-Djava.rmi.server.hostname" worked like a charm for me ! – Orhun D. Apr 09 '17 at 13:20
  • Was using Ubuntu 14.04 and everything worked out-of-the-box. Moved to Debian jessie and I had to do everything explained in this answer – numéro6 Jun 19 '17 at 09:51
  • 1
    setting the hostname to localhost is very important if you are trying to connect a to a remote server through SSH tunnel, which is a very common case. – Nikhil Owalekar Aug 04 '17 at 18:10
  • 1
    That works only if I disable the firewall on the server. I opened the port 9010/tcp in this example of course, I also tried to add `Dcom.sun.management.jmxremote.rmi.port=9011` and open in firewall - still cant connect with the firewall being up. Any thoughts? Have I missed anything? – Carmageddon Dec 06 '18 at 15:05
  • @Carmageddon `-Dcom.sun.management.jmxremote.rmi.port=[...]` in combination with `-Djava.rmi.server.hostname=[...]` should work. Without those both I ran into similar issues, so make sure that your configured port for `.rmi.port` is really accessible by your client AND the same for the configured `.hostname`! Without the latter explicitly defined, Java will assume some IP it things is the primary interface of the server, which might still be blocked in your firewall. Without the port it assumes some random one. You might use Wireshark or Process Monitor to debug connections of client/server. – Thorsten Schöning Apr 29 '19 at 13:12
  • `java.rmi.server.hostname` The value of this property represents the host name string that should be associated with remote stubs for locally created remote objects, in order to allow clients to invoke methods on the remote object. The default value of this property is the IP address of the local host, in "dotted-quad" format. https://docs.oracle.com/javase/8/docs/technotes/guides/rmi/javarmiproperties.html – Thorsten Schöning Apr 29 '19 at 13:13
  • In case you already have access to the server using ssh, you don't need to mess with the firewall, just create a bridge: `ssh -g -L :localhost: @`. Example: `ssh -g -L 9523:localhost:9523 my-linux-account@5.23.56.78` then go to the `jvisualvm` and add a JMX connection as `localhost:9523`. Don't forget to add: `-Djava.rmi.server.hostname=127.0.0.1` in your remote server, because without it, it won't work. – Edenshaw Mar 13 '20 at 17:45
72

Running in a Docker container introduced a whole slew of additional problems for connecting so hopefully this helps someone. I ended up needed to add the following options which I'll explain below:

-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=${DOCKER_HOST_IP}
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.rmi.port=9998

DOCKER_HOST_IP

Unlike using jconsole locally, you have to advertise a different IP than you'll probably see from within the container. You'll need to replace ${DOCKER_HOST_IP} with the externally resolvable IP (DNS Name) of your Docker host.

JMX Remote & RMI Ports

It looks like JMX also requires access to a remote management interface (jstat) that uses a different port to transfer some data when arbitrating the connection. I didn't see anywhere immediately obvious in jconsole to set this value. In the linked article the process was:

  • Try and connect from jconsole with logging enabled
  • Fail
  • Figure out which port jconsole attempted to use
  • Use iptables/firewall rules as necessary to allow that port to connect

While that works, it's certainly not an automatable solution. I opted for an upgrade from jconsole to VisualVM since it let's you to explicitly specify the port on which jstatd is running. In VisualVM, add a New Remote Host and update it with values that correlate to the ones specified above:

Add Remote Host

Then right-click the new Remote Host Connection and Add JMX Connection...

Add JMX Connection

Don't forget to check the checkbox for Do not require SSL connection. Hopefully, that should allow you to connect.

Joshua Taylor
  • 80,876
  • 9
  • 135
  • 306
Joel B
  • 8,705
  • 9
  • 51
  • 63
  • `-Djava.rmi.server.hostname=localhost` `-Dcom.sun.management.jmxremote.rmi.port=[...]` is as well the key in case of tunnelling JMX/RMI through SSH. Without those, remote objects are accessed using the public/main/... IP of the server using some random port, which can't be forwarded easily. – Thorsten Schöning Apr 29 '19 at 13:17
  • 1
    I can confirm that you really need to use the external to container IP. For example it doesn't work with `-Djava.rmi.server.hostname=0.0.0.0` – raisercostin May 19 '19 at 15:56
  • I didn't need to use `DOCKER_HOST_IP` anywhere - I just used `localhost` and forwarded the ports when running the docker image: `-p 9998:9998, -p 9999:9999` etc. – Barney Aug 06 '19 at 03:23
  • This also worked for my Docker-Java-Setup. It would be easier to mention that the `jstatd` port is equivalent to the `-Dcom.sun.management.jmxremote.rmi.port` parameter. It is not explicitly stated, but it would improve the quality of your answer. Thanks! – Webchen Mar 31 '21 at 22:22
10

Note, Java 6 in the latest incarnation allows for jconsole to attach itself to a running process even after it has been started without JMX incantations.

If that is available to you, also consider jvisualvm as it provides a wealth of information on running processes, including a profiler.

Thorbjørn Ravn Andersen
  • 68,906
  • 28
  • 171
  • 323
  • 4
    This only works if you are running jconsole on the same host as the JVM you are trying to monitor. – Gray Mar 01 '14 at 18:12
  • 1
    @ Thorbjorn If i start my java program without any parameters and try to connect with jconsole, I see in my program in the list but when I try to connect it fails. I think it is because of lack of SSL certificates. I just wanted to see the demo hence I had to use the parameters specified in the answer by user3013578 and it worked for me (JDK 1.7 , Windows 8.1, 64 bit). – Dattaprasad Choukekar Jul 19 '15 at 11:43
  • 2
    The attach API requires jconsole to have the same 32/64 bit JVM as the launched program on some platforms. – Thorbjørn Ravn Andersen Jul 19 '15 at 15:34
  • 1
    Is it possible to disable this behaviour? – kevinarpe Nov 15 '15 at 12:29
7

I'm using WAS ND 7.0

My JVM need all the following arguments to be monitored in JConsole

    -Djavax.management.builder.initial= 
    -Dcom.sun.management.jmxremote 
    -Dcom.sun.management.jmxremote.port=8855 
    -Dcom.sun.management.jmxremote.authenticate=false 
    -Dcom.sun.management.jmxremote.ssl=false
valentin_nasta
  • 596
  • 4
  • 20
user3013578
  • 71
  • 1
  • 1
6

On Linux, I used the following params:

-Djavax.management.builder.initial= 
-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9010 
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false 
-Dcom.sun.management.jmxremote.ssl=false

and also I edited /etc/hosts so that the hostname resolves to the host address (192.168.0.x) rather than the loopback address (127.0.0.1)

Gray
  • 108,756
  • 21
  • 270
  • 333
alex.pulver
  • 2,031
  • 2
  • 28
  • 28
2

Run your java application with the following command line parameters:

-Dcom.sun.management.jmxremote.port=8855
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false

It is important to use the -Dcom.sun.management.jmxremote.ssl=false parameter if you don't want to setup digital certificates on the jmx host.

If you started your application on a machine having IP address 192.168.0.1, open jconsole, put 192.168.0.1:8855 in the Remote Process field, and click Connect.

Wasif
  • 151
  • 5
  • What is the expected behavior if you forget `-Dcom.sun.management.jmxremote.ssl=false`? Should `jconsole` show an error, or would it just quietly fail to connect? – amacleod Nov 03 '14 at 19:16
2

along with below command line parameters ,

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

Sometimes in the linux servers , imx connection doesn't get succeeded. that is because , in cloud linux host, in /etc/hosts so that the hostname resolves to the host address.

the best way to fix it is, ping the particular linux server from other machine in network and use that host IP address in the

-Djava.rmi.server.hostname=IP address that obtained when you ping that linux server.

But never rely on the ipaddress that you get from linux server using ifconfig.me. the ip that you get there is masked one which is present in the host file.

Phani Kumar
  • 41
  • 2
  • 10
2

Step 1: Run the application using following parameters.

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

Above arguments bind the application to the port 9999.

Step 2: Launch jconsole by executing the command jconsole in command prompt or terminal.

Select ‘Remote Process:’ and enter the url as {IP_Address}:9999 and click on Connect button to connect to the remote application.

You can refer this link for complete application.

Hari Krishna
  • 2,599
  • 19
  • 37
2

The below options works for me:

-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.port=9010
-Dcom.sun.management.jmxremote.rmi.port=9010
-Dcom.sun.management.jmxremote.local.only=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname={host name}

and remember to open 9010 port in the server

sudo ufw allow 9010/udp
sudo ufw allow 9010/tcp
sudo ufw reload
Russell Bie
  • 146
  • 1
  • 8
1

First you need to check if your java process is already running with JMX parameters. Do this:

ps -ef | grep java

Check your java process you need to monitor. If you can see jmx rmi parameter Djmx.rmi.registry.port=xxxx then use the port mentioned here in your java visualvm to connect it remotely under jmx connection.

If it's not running through jmx rmi port then you need to run your java process with below mentioned parameters :

-Djmx.rmi.registry.port=1234 -Djmx.rmi.port=1235 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false

Note: port numbers are based on your choice.

Now you can use this port for jmx coneection. Here it is port 1234.

machnic
  • 1,867
  • 1
  • 16
  • 20
Abhay Singh
  • 61
  • 1
  • 6
0

I had this exact issue, and created a GitHub project for testing and figuring out the correct settings.

It contains a working Dockerfile with supporting scripts, and a simple docker-compose.yml for quick testing.

cstroe
  • 2,537
  • 1
  • 21
  • 14
0

RUN LOCAL PROCESS JCONSOLE using Remote Process option

To run locally, this worked for me -

I added this in my vm args -

-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.port=6001
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
-Djava.rmi.server.hostname=localhost
-Dcom.sun.management.jmxremote.rmi.port=6001

I opened JConsole via Intellij Terminal
It was showing me all PID's in grey in local
So I selected remote process and logged in using host - localhost:6001
Keep empty username & password
Then click connect
  • Make sure no other process is running on port 6001. You can also use other ports.
Archit Puri
  • 160
  • 1
  • 8