jps工具用来列举系统中正在运行的java进程,和unix命令ps类似。
命令格式
usage: jps [-help]
jps [-q] [-mlvV] [<hostid>]
Definitions:
<hostid>: <hostname>[:<port>]
- -q选项:不输出类名,JAR文件名称和应用程序主方法的参数,仅列出pid。
- -m选项:输出传递到应用程序主方法的参数。
- -l选项:输出应用程序主类的完整包名。
- -v选项:输出虚拟机参数
- -V选项:输出通过标识文件传递给虚拟机的参数。
源码路径
openjdk/jdk/src/share/classes/sun/tools/jps/Jps.java
openjdk/jdk/src/share/classes/sun/tools/jps/Arguments.java
源码
package sun.tools.jps;
import java.util.*;
import java.net.*;
import sun.jvmstat.monitor.*;
/**
* Application to provide a listing of monitorable java processes.
*
* @author Brian Doherty
* @since 1.5
*/
public class Jps {
private static Arguments arguments;
public static void main(String[] args) {
//命令行参数判断
try {
arguments = new Arguments(args);
} catch (IllegalArgumentException e) {
System.err.println(e.getMessage());
Arguments.printUsage(System.err);
System.exit(1);
}
//命令行参数判断
if (arguments.isHelp()) {
Arguments.printUsage(System.err);
System.exit(0);
}
try {
HostIdentifier hostId = arguments.hostId();
MonitoredHost monitoredHost =
MonitoredHost.getMonitoredHost(hostId);
// get the set active JVMs on the specified host.
Set<Integer> jvms = monitoredHost.activeVms();
for (Integer jvm: jvms) {
StringBuilder output = new StringBuilder();
Throwable lastError = null;
int lvmid = jvm;
output.append(String.valueOf(lvmid));
if (arguments.isQuiet()) {
System.out.println(output);
continue;
}
MonitoredVm vm = null;
String vmidString = "//" + lvmid + "?mode=r";
String errorString = null;
try {
// Note: The VM associated with the current VM id may
// no longer be running so these queries may fail. We
// already added the VM id to the output stream above.
// If one of the queries fails, then we try to add a
// reasonable message to indicate that the requested
// info is not available.
errorString = " -- process information unavailable";
VmIdentifier id = new VmIdentifier(vmidString);
/*
获得MonitorVm,并且创建了perfData缓存。
MonitorVm通过解析目标主机的PerfData共享数据,
将PerfData数据写入Man<String,Monitor>中,
这个map称为monitors<PerfDataBufferImpl类成员变量>
*/
vm = monitoredHost.getMonitoredVm(id, 0);
//这部分为对命令行参数结果的最终展示,调用了MonitoredVmUtil类
errorString = " -- main class information unavailable";
output.append(" " + MonitoredVmUtil.mainClass(vm,
arguments.showLongPaths()));
if (arguments.showMainArgs()) {
errorString = " -- main args information unavailable";
String mainArgs = MonitoredVmUtil.mainArgs(vm);
if (mainArgs != null && mainArgs.length() > 0) {
output.append(" " + mainArgs);
}
}
if (arguments.showVmArgs()) {
errorString = " -- jvm args information unavailable";
String jvmArgs = MonitoredVmUtil.jvmArgs(vm);
if (jvmArgs != null && jvmArgs.length() > 0) {
output.append(" " + jvmArgs);
}
}
if (arguments.showVmFlags()) {
errorString = " -- jvm flags information unavailable";
String jvmFlags = MonitoredVmUtil.jvmFlags(vm);
if (jvmFlags != null && jvmFlags.length() > 0) {
output.append(" " + jvmFlags);
}
}
errorString = " -- detach failed";
monitoredHost.detach(vm);
System.out.println(output);
errorString = null;
} catch (URISyntaxException e) {
// unexpected as vmidString is based on a validated hostid
lastError = e;
assert false;
} catch (Exception e) {
lastError = e;
} finally {
if (errorString != null) {
/*
* we ignore most exceptions, as there are race
* conditions where a JVM in 'jvms' may terminate
* before we get a chance to list its information.
* Other errors, such as access and I/O exceptions
* should stop us from iterating over the complete set.
*/
output.append(errorString);
if (arguments.isDebug()) {
if ((lastError != null)
&& (lastError.getMessage() != null)) {
output.append("\n\t");
output.append(lastError.getMessage());
}
}
System.out.println(output);
if (arguments.printStackTrace()) {
lastError.printStackTrace();
}
continue;
}
}
}
} catch (MonitorException e) {
if (e.getMessage() != null) {
System.err.println(e.getMessage());
} else {
Throwable cause = e.getCause();
if ((cause != null) && (cause.getMessage() != null)) {
System.err.println(cause.getMessage());
} else {
e.printStackTrace();
}
}
System.exit(1);
}
}
}
从main()函数可以看出,jps利用了辅助工具类MonitoredVmUtil,获得展示信息。MonitoredVmUtil.java中实现了一些列获得虚拟机监视器信息的接口方法,这些方法通过读取并解析共享内存PerfMemory的命名变量,能够捕获虚拟机监视器信息。
- "java.property.java.vm.version" :虚拟机版本
- "sun.rt.javaCommand":命令行
- "java.rt.vmArgs":虚拟机参数
- "java.rt.vmFlags":虚拟机选项
- ......
【路径:openjdk/jdk/src/share/classes/sun/jvmstat/monitor/MonitoredVmUtil.java】
根据监视器名称获取指定监视器,有两种查找方法, 分别为findByName()函数[通过完整的monitor名称查找], 和findByPattern()函数[通过正则查找]。
public static String vmVersion(MonitoredVm vm) throws MonitorException {
StringMonitor ver =
(StringMonitor)vm.findByName("java.property.java.vm.version");
return (ver == null) ? "Unknown" : ver.stringValue();
}
public static String commandLine(MonitoredVm vm) throws MonitorException {
StringMonitor cmd = (StringMonitor)vm.findByName("sun.rt.javaCommand");
return (cmd == null) ? "Unknown" : cmd.stringValue();
}
public static String jvmArgs(MonitoredVm vm) throws MonitorException {
StringMonitor jvmArgs = (StringMonitor)vm.findByName("java.rt.vmArgs");
return (jvmArgs == null) ? "Unknown" : jvmArgs.stringValue();
}
public static String jvmFlags(MonitoredVm vm) throws MonitorException {
StringMonitor jvmFlags =
(StringMonitor)vm.findByName("java.rt.vmFlags");
return (jvmFlags == null) ? "Unknown" : jvmFlags.stringValue();
}
结束语
除了上述监视器之外,还有一些隐藏的监视器,所以可以通过修改openjdk源码,扩展jps的功能,获取更多信息。下一篇文章将详细讲解如何扩展jps功能。