Profiling Remote Java Application
29 September 2017
jvisualvm
is a tool that provides a visual interface for viewing detailed information about Java technology-based applications while they are running. You can his to view data related to your local applications and those running on remote hosts. You can also capture data about JVM software instances and save the data to your local system.
There are couple of ways to use it, one is using jstatd
and the other is by JMX (Java management Extensions). I tried jstatd first but didn't work. The later worked on my CentOS machine using the visualvm I downloaded from visualvm.github.io.
By using jstatd
Grant jstatd full security permission
Create a file called jstatd.all.policy
. If in production, make sure your server port are locked down to your local IP.
grant codebase "file:/opt/java8/lib/tools.jar" {
permission java.security.AllPermission;
};
Please use the full-path of your JDK's tools.jar. The above policy should avoid you from getting this access denied message
Could not create remote object
access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write")
java.security.AccessControlException: access denied ("java.util.PropertyPermission" "java.rmi.server.ignoreSubClasses" "write")
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
at java.security.AccessController.checkPermission(AccessController.java:884)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at java.lang.System.setProperty(System.java:792)
at sun.tools.jstatd.Jstatd.main(Jstatd.java:139)
Run jstatd
jstatd -J-Djava.security.policy=/home/user/jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.1.1 -J-Djava.net.preferIPv4Stack=true -J-Djava.rmi.server.logCalls=true
Replace /home/user/jstatd.all.policy
by your actual file and 192.168.1.1 by the remote IP of your target machine.
By using JMX
Add some JVM arguments
-Dcom.sun.management.jmxremote=true
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.port=1098
-Dcom.sun.management.jmxremote.rmi.port=1098
-Djava.rmi.server.hostname=localhost
If running CentOS, run this to open up port 1098.
sudo firewall-cmd --zone=public --add-port=1098/tcp
Launch SSH with local port forwarding
ssh -v -L 1098:localhost:1098 user@my.remote.server.com
Replace user by your login and my.remote.server.com by your own hostname or IP address. Since I'm running SSH in verbose mode, you should see debug messages like below.
debug1: channel 6: free: direct-tcpip: listening port 1098 for localhost port 1098, connect from 127.0.0.1 port 8077 to 127.0.0.1 port 9001, nchannels 9
debug1: channel 8: free: direct-tcpip: listening port 1098 for localhost port 1098, connect from 127.0.0.1 port 8078 to 127.0.0.1 port 9001, nchannels 8
debug1: channel 4: free: direct-tcpip: listening port 1098 for localhost port 1098, connect from 127.0.0.1 port 8073 to 127.0.0.1 port 9001, nchannels 7
Connect VisualVM to Local
Right-click on Local -> Add JMX Connection. On connection type localhost:1098
Alternative to VisualVM
Run jconsole
. On Remote Process, type localhost:1098