Detecting all running JVMs
Several well known JVM tools appear to be able to magically detect the Java processes running on a system. Good examples of this are: jps and Visual VM. As of Java 6 it is even possible to find out yourself which Java processes are running on the local machine that you have access to using the Dynamic Attach API. These APIs can be found in the tools.jar (JAVA_HOME/lib/tools.jar).
The following code illustrates how the Dynamic Attach API can be used to list all of the local virtual machine identifiers (which for the HotSpot VM map onto the JVM PID):
package uk.co.cooljeff.dynamicattach; import java.util.List; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; public class JVMFinder { public static void main(String[] args) { List<VirtualMachineDescriptor> vmDescriptors = VirtualMachine.list(); for (VirtualMachineDescriptor vmDescriptor : vmDescriptors) { System.out.println("Name: " + vmDescriptor.displayName() + " PID: " + vmDescriptor.id()); } } }
The above gives the following output on my machine (cut out a few for brevity):
Name: uk.co.cooljeff.dynamicattach.JVMFinder PID: 21116
I’m about to spoil the fun now for those of you who were hoping to see some wacky OS dependent mechanism or hidden RMI registry for finding this information. The solution is quite simple, the JVM dumps a file containing performance data to a standard location which it uses to work out what JVMs are running on a host.
Specifically the performance data is for jvmstat, however it is this file that forms the basis of the Dynamic Attach implementation that HotSpot uses.
The following piece of code replicates what the LocalVmManager (part of jvmstat) does to locate running Java processes:
package uk.co.cooljeff.dynamicattach; import java.io.File; import java.io.FilenameFilter; import java.util.regex.Matcher; import java.util.regex.Pattern; import sun.jvmstat.perfdata.monitor.protocol.local.PerfDataFile; public class JVMDataLocation { public static void main(String[] args) throws Exception { final Pattern filePattern = Pattern.compile(PerfDataFile.userDirNamePattern); final Matcher fileMatcher = filePattern.matcher(""); FilenameFilter fileFilter = new FilenameFilter() { public boolean accept(File dir, String name) { fileMatcher.reset(name); return fileMatcher.matches(); } }; File[] files = new File(PerfDataFile.getTempDirectory()).listFiles(fileFilter); for (File file : files) { System.out.println("PerfDataDir: " + file); } } }
Which gives the following on my machine:
PerfDataDir: /tmp/hsperfdata_root PerfDataDir: /tmp/hsperfdata_tomcat55 PerfDataDir: /tmp/hsperfdata_jeffsinc
If you take a look at one of these directories you will find 1 file per Java process running by the specific user. The name of the file is the local virtual machine identifier (lvmid) which for HotSpot will correspond to the process id. If you run strings on the file you will see all of the properties relating to that JVM instance.
It is as simple as that, on Linux the JVM simply looks for all files that match: /tmp/hsperfdata_*/*.
Resources: