Skip to content

jcmd jps

wangkaiwu edited this page May 29, 2022 · 4 revisions

jps

下面的内容涉及到了 MonitoredVM源码解析 的内容

显示样例

$ jps -l
65416 jdk.jcmd/sun.tools.jps.Jps

显示的源码

位于 openJdk 的 jdk.jcmd 包中

package sun.tools.jps;

public class Jps {
    private static Arguments arguments;

    public static void main(String[] args) {
        // 组装参数
        arguments = new Arguments(args);
        HostIdentifier hostId = arguments.hostId();
        MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(hostId);
        Set<Integer> jvms = monitoredHost.activeVms();
        for (Integer jvm : jvms) {
            StringBuilder output = new StringBuilder();
            int lvmid = jvm;
            output.append(String.valueOf(lvmid));
            if (arguments.isQuiet()) {
                System.out.println(output);
                continue;
            }
            MonitoredVm vm = null;
            String vmidString = "//" + lvmid + "?mode=r";
            VmIdentifier id = new VmIdentifier(vmidString);
            vm = monitoredHost.getMonitoredVm(id, 0);
            output.append(' ').append(MonitoredVmUtil.mainClass(vm,
                    arguments.showLongPaths()));
            if (arguments.showMainArgs()) {
                String mainArgs = MonitoredVmUtil.mainArgs(vm);
                output.append(' ').append(mainArgs);
            }
            if (arguments.showVmArgs()) {
                String jvmArgs = MonitoredVmUtil.jvmArgs(vm);
                output.append(' ')
                        .append(
                                // multi-line args are permitted
                                jvmArgs.replace("\n", "\\n").replace("\r", "\\r")
                        );
            }
            if (arguments.showVmFlags()) {
                String jvmFlags = MonitoredVmUtil.jvmFlags(vm);
                output.append(' ').append(jvmFlags);
            }
            monitoredHost.detach(vm);
            System.out.println(output);
        }
    }
}

参数初始化

public class Arguments {
    private boolean help;
    private boolean quiet;
    private boolean longPaths;
    private boolean vmArgs;
    private boolean vmFlags;
    private boolean mainArgs;
    private String hostname;
    private HostIdentifier hostId;

    public Arguments(String[] args) throws IllegalArgumentException {
        int argc = 0;
        for (argc = 0; (argc < args.length) && (args[argc].startsWith("-"));
             argc++) {
            String arg = args[argc];
            // -q 的意思就是 只输出进程ID
            if (arg.compareTo("-q") == 0) {
                quiet = true;
            } else if (arg.startsWith("-")) {
                for (int j = 1; j < arg.length(); j++) {
                    switch (arg.charAt(j)) {
                        case 'm':
                            mainArgs = true;
                            break;
                        case 'l':
                            longPaths = true;
                            break;
                        case 'v':
                            vmArgs = true;
                            break;
                        case 'V':
                            vmFlags = true;
                            break;
                    }
                }
            }
        }
        switch (args.length - argc) {
            case 0:
                // hostname 会当做 //localhost
                hostname = null;
                break;
            case 1:
                // 最后一个参数会当做 hostname, 格式为 //
                hostname = args[args.length - 1];
                break;
        }
        hostId = new HostIdentifier(hostname);
    }
}

MonitoredHost 与 临时目录

临时目录

ceragon@ceragon-ThinkPad-T440p:/tmp/hsperfdata_ceragon$ ls
12268  386347
ceragon@ceragon-ThinkPad-T440p:/tmp/hsperfdata_ceragon$ jps -l
405830 jdk.jcmd/sun.tools.jps.Jps
12268 
386347 com.intellij.idea.Main

MonitoredHost

public abstract class MonitoredHost {
    private static ServiceLoader<MonitoredHostService> monitoredHostServiceLoader =
            ServiceLoader.load(MonitoredHostService.class, MonitoredHostService.class.getClassLoader());

    public static MonitoredHost getMonitoredHost(HostIdentifier hostId) throws MonitorException {
        for (MonitoredHostService mhs : monitoredHostServiceLoader) {
            if (mhs.getScheme().equals(hostId.getScheme())) {
                mh = mhs.getMonitoredHost(hostId);
            }
        }
    }
}
public final class MonitoredHostLocalService implements MonitoredHostService {
    @Override
    public MonitoredHost getMonitoredHost(HostIdentifier hostId) throws MonitorException {
        return new MonitoredHostProvider(hostId);
    }
}

存放JVM进程信息的临时目录

public class MonitoredHostProvider extends MonitoredHost {
    private LocalVmManager vmManager;

    public MonitoredHostProvider(HostIdentifier hostId) {
        this.vmManager = new LocalVmManager();
    }

    public Set<Integer> activeVms() {
        return vmManager.activeVms();
    }
}
public class LocalVmManager {
    private List<String> tmpdirs;

    public LocalVmManager() {
        this(null);
    }

    public LocalVmManager(String user) {
        this.userName = user;
        if (userName == null) {
            tmpdirs = PerfDataFile.getTempDirectories(null, 0);
        }
    }
}

获取操作系统的临时路径 tmpdirs

public class PerfDataFile {
    private static final PlatformSupport platSupport = PlatformSupport.getInstance();

    public static List<String> getTempDirectories(String userName, int vmid) {
        List<String> list = platSupport.getTemporaryDirectories(vmid);
        if (userName == null) {
            return list;
        }
    }
}
public class PlatformSupport {
    private static final String tmpDirName;

    static {
        // 从上面的例子来看,linux 下 tmpdir = /tmp/hsperfdata_ceragon
        String tmpdir = VMSupport.getVMTemporaryDirectory();
        tmpDirName = tmpdir;
    }

    public List<String> getTemporaryDirectories(int vmid) {
        return List.of(tmpDirName);
    }
}

获取所有的 jvm 进程

示例

ceragon@ceragon-ThinkPad-T440p:/tmp/hsperfdata_ceragon$ ls
12268  386347

代码

public class MonitoredHostProvider extends MonitoredHost {
    private LocalVmManager vmManager;

    public Set<Integer> activeVms() {
        return vmManager.activeVms();
    }
}
public class LocalVmManager {
    private FilenameFilter fileFilter;
    private Pattern filePattern;
    private Matcher fileMatcher;
    // 上面已经分析了 临时路径的获取方法
    private List<String> tmpdirs;

    public LocalVmManager() {
        this(null);
    }

    public LocalVmManager(String user) {
        // fileNamePattern = "^[0-9]+$"
        filePattern = Pattern.compile(PerfDataFile.fileNamePattern);
        fileMatcher = filePattern.matcher("");
        fileFilter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                fileMatcher.reset(name);
                return fileMatcher.matches();
            }
        };
    }

    public synchronized Set<Integer> activeVms() {
        Set<Integer> jvmSet = new HashSet<>();
        for (String dir : tmpdirs) {
            File tmpdir = new File(dir);
            if (userName == null) {
                // 找出当前用户可用的目录
                File[] dirs = tmpdir.listFiles(userFilter);
                for (int i = 0; i < dirs.length; i++) {
                    // 目录中的所有文件
                    File[] files = dirs[i].listFiles(fileFilter);
                    for (int j = 0; j < files.length; j++) {
                        if (files[j].isFile() && files[j].canRead()) {
                            int vmid = PerfDataFile.getLocalVmId(files[j]);
                            jvmSet.add(vmid);
                        }
                    }
                }
            }
        }
        return jvmSet;
    }
}
public class PerfDataFile {
    private static final PlatformSupport platSupport = PlatformSupport.getInstance();

    public static int getLocalVmId(File file) {
        return (platSupport.getLocalVmId(file));
    }
}
public class PlatformSupportImpl extends PlatformSupport {
    public int getLocalVmId(File file) throws NumberFormatException {
        String p = file.getAbsolutePath();
        String s[] = p.split("\\/");
        if (s.length == 7 && s[1].equals("proc")) {
            int hostpid = Integer.parseInt(s[2]);
            int nspid = Integer.parseInt(s[6]);
            if (nspid == hostpid || nspid == getNamespaceVmId(hostpid)) {
                return hostpid;
            }
            return -1;
        }
        return Integer.parseInt(file.getName());
    }
}

-l 参数获取 mainClass 全路径

public class MonitoredVmUtil {
    public static String mainClass(MonitoredVm vm, boolean fullPath) throws MonitorException {
        String cmdLine = commandLine(vm);
        int firstSpace = cmdLine.indexOf(' ');
        if (firstSpace > 0) {
            cmdLine = cmdLine.substring(0, firstSpace);
        }
        if (fullPath) {
            return cmdLine;
        }
    }

    public static String commandLine(MonitoredVm vm) throws MonitorException {
        StringMonitor cmd = (StringMonitor) vm.findByName("sun.rt.javaCommand");
        return (cmd == null) ? "Unknown" : cmd.stringValue();
    }
}

-m 参数获取主函数的参数

public class MonitoredVmUtil {
    public static String mainArgs(MonitoredVm vm) throws MonitorException {
        String commandLine = commandLine(vm);
        int firstSpace = commandLine.indexOf(' ');
        return commandLine.substring(firstSpace + 1);
    }

    public static String commandLine(MonitoredVm vm) throws MonitorException {
        StringMonitor cmd = (StringMonitor) vm.findByName("sun.rt.javaCommand");
        return (cmd == null) ? "Unknown" : cmd.stringValue();
    }
}

-v 获取 vm 的参数

public class MonitoredVmUtil {
    public static String jvmArgs(MonitoredVm vm) throws MonitorException {
        StringMonitor jvmArgs = (StringMonitor) vm.findByName("java.rt.vmArgs");
        return (jvmArgs == null) ? "Unknown" : jvmArgs.stringValue();
    }
}

-V 获取 vm 的所有配置

public class MonitoredVmUtil {
    public static String jvmFlags(MonitoredVm vm) throws MonitorException {
        StringMonitor jvmFlags =
                (StringMonitor) vm.findByName("java.rt.vmFlags");
        return (jvmFlags == null) ? "Unknown" : jvmFlags.stringValue();
    }
}

涉及到的 JVM 的 PerfDataEntry

void StatSampler::create_misc_perfdata() {
    PerfDataManager::create_string_constant(JAVA_RT, "vmFlags",
                                          Arguments::jvm_flags(), CHECK);
    PerfDataManager::create_string_constant(JAVA_RT, "vmArgs",
                                          Arguments::jvm_args(), CHECK);
    PerfDataManager::create_string_constant(SUN_RT, "javaCommand",
                                          Arguments::java_command(), CHECK);
}

Clone this wiki locally