Java系统工具jps原理解析
来源:互联网 发布:讲文明知礼仪手抄报 编辑:程序博客网 时间:2024/06/15 15:46
Java系统工具jps原理解析
简介
当我们需要获取当前正在运行的Java进程时,我们可以通过操作系统自带的工具来筛选,如ps和netstat等。不过Java也提供了通用的工具来实现该功能,而且能够提供更加详细的信息。jps是Java Virtual Machine Process Status Too的简称,可以用来获取当前用户系统中的Java进程。
使用
jps的命令格式为 jps [ options ] [ hostid ]
,具体形式如下:
usage: jps [-help] jps [-q] [-mlvV] [<hostid>]Definitions: <hostid>: <hostname>[:<port>]
其中的参数解释如下(其中mlvV可以组合使用):
- q:只显示Java进程的lvmid,不显示class名称、jar文件名和传递给main 方法的参数等
- m:输出传递给main方法的参数
- l:输出应用程序入口函数的完整package名或者应用程序的jar文件完整路径名
- v:输出传递给JVM的参数
- V:通过标识文件来输出传递给JVM的参数(即.hotspotrc文件或者由参数-XX:Flags=确定的文件)
- hostid:需要查看Java进程的系统,由主机名和端口号来确定
注:查看本地Java进程不需要hostid参数,如果要查看远程进程,需要在远程主机提供jstatd服务和RMI绑定,稍后会介绍jstatd
jps的输出结果格式为 lvmid [ [ classname | JARfilename | "Unknown"] [ arg* ] [ jvmarg* ] ]
,下面是在Ubuntu系统中进行的测试实例:
shenjie@ubuntu:~$ jps3540 org.eclipse.equinox.launcher_1.3.0.v20140415-2008.jar3669 Main4535 Jpsshenjie@ubuntu:~$ jps -m4548 Jps -m3540 org.eclipse.equinox.launcher_1.3.0.v20140415-2008.jar -os linux -ws gtk -arch x86_64 -showsplash /usr/share/eclipse//plugins/org.eclipse.platform_4.4.2.v20150204-1700/splash.bmp -launcher /usr/share/eclipse/eclipse -name Eclipse --launcher.library /usr/share/eclipse//plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.200.v20150204-1316/eclipse_1607.so -startup /usr/share/eclipse//plugins/org.eclipse.equinox.launcher_1.3.0.v20140415-2008.jar --launcher.appendVmargs -exitdata 220011 -product org.eclipse.epp.package.java.product -vm /usr/bin/java -vmargs -Dosgi.requiredJavaVersion=1.6 -XX:MaxPermSize=256m -Xms40m -Xmx512m -jar /usr/share/eclipse//plugins/org.eclipse.equinox.launcher_1.3.0.v20140415-2008.jar3669 Mainshenjie@ubuntu:~$ jps -l4738 sun.tools.jps.Jps3540 /usr/share/eclipse//plugins/org.eclipse.equinox.launcher_1.3.0.v20140415-2008.jar3669 local.Mainshenjie@ubuntu:~$ jps -v3540 org.eclipse.equinox.launcher_1.3.0.v20140415-2008.jar -Dosgi.requiredJavaVersion=1.6 -XX:MaxPermSize=256m -Xms40m -Xmx512m3669 Main -Dfile.encoding=UTF-84907 Jps -Dapplication.home=/usr/lib/jvm/jdk1.8.0_45 -Xms8m
原理
下面解析一下jps如何实现的,参看的代码来自openjdk7。我们从入口类Jps.java看起,这个类中就一个Main方法,核心的代码如下图所示,首先从特定的主机上获取正在运行的Java进程,然后对这些进程进行输出,如果有参数的话还要额外输出参数需要输出的信息。从主机获取Java进程主要有分为两种,一种是本地的,另一种通过RMI远程调用的。
HostIdentifier hostId = arguments.hostId(); MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(hostId); // 从特定主机上获取Java进程 Set jvms = monitoredHost.activeVms(); for (Iterator j = jvms.iterator(); j.hasNext(); /* empty */ ) { StringBuilder output = new StringBuilder(); Throwable lastError = null; int lvmid = ((Integer)j.next()).intValue(); output.append(String.valueOf(lvmid)); if (arguments.isQuiet()) { System.out.println(output); continue; } MonitoredVm vm = null; String vmidString = "//" + lvmid + "?mode=r"; String errorString = null; // 处理其他参数 }
我们主要看一下从本地获取Java进程的代码,monitoredHost.activeVms()方法最后通过LocalVmManager中的activeVms()来实现。通过看下面的代码,我们容易发现最后返回的lvmid集合jvmSet中的元素都是通过类似PerfDataFile.getLocalVmId(files[j])
的方法添加的,而这些files的文件夹也是通过类PerfDataFile中的函数PerfDataFile.getTempDirectory(userName)
得来的。细心的同学应该发现文件夹的结构会根据有无用户名而发生变化,而通过PerfDataFile中的代码可以发现该文件夹下的文件名也有着两种不同的标准。接下去我们继续看类PerfDataFile。
public synchronized Set<Integer> activeVms() { /* * This method is synchronized because the Matcher object used by * fileFilter is not safe for concurrent use, and this method is * called by multiple threads. Before this method was synchronized, * we'd see strange file names being matched by the matcher. */ Set<Integer> jvmSet = new HashSet<Integer>(); if (! tmpdir.isDirectory()) { return jvmSet; } if (userName == null) { /* * get a list of all of the user temporary directories and * iterate over the list to find any files within those directories. */ File[] dirs = tmpdir.listFiles(userFilter); for (int i = 0 ; i < dirs.length; i ++) { if (!dirs[i].isDirectory()) { continue; } // get a list of files from the directory File[] files = dirs[i].listFiles(fileFilter); if (files != null) { for (int j = 0; j < files.length; j++) { if (files[j].isFile() && files[j].canRead()) { jvmSet.add(new Integer( PerfDataFile.getLocalVmId(files[j]))); } } } } } else { /* * Check if the user directory can be accessed. Any of these * conditions may have asynchronously changed between subsequent * calls to this method. */ // get the list of files from the specified user directory File[] files = tmpdir.listFiles(fileFilter); if (files != null) { for (int j = 0; j < files.length; j++) { if (files[j].isFile() && files[j].canRead()) { jvmSet.add(new Integer( PerfDataFile.getLocalVmId(files[j]))); } } } } // look for any 1.4.1 files File[] files = tmpdir.listFiles(tmpFileFilter); if (files != null) { for (int j = 0; j < files.length; j++) { if (files[j].isFile() && files[j].canRead()) { jvmSet.add(new Integer( PerfDataFile.getLocalVmId(files[j]))); } } } return jvmSet; }}
类PerfDataFile提供了Java进程与文件相互转换的方法。从该类中可以找到各系统下这些文件的对应位置,如方法getTempDirectory所示,该临时目录的路径如下: tmpDirName + dirNamePrefix + user + File.separator
,其中tmpDirName为Java io对应的临时文件,dirNamePrefix固定为”hsperfdata_”,user是系统用户名,File.separator是文件分隔符。在Windows系统下,默认路径为 C:\Users\username\AppData\Local\Temp\hsperfdata_username
,而在Linux系统下,默认路径为/tmp/hsperfdata_username
。在这些文件夹下的文件会在对应的Java进程结束被清除。方法getLocalVmId是用来从进程文件得到lvmid,可以看出1.4.2版本及以后的HotSpot虚拟机直接以lvmid为名字,之前的版本中拥有分隔符。
注:Windows中的临时文件可能为隐藏文件
public static String getTempDirectory(String user) { return tmpDirName + dirNamePrefix + user + File.separator; } public static int getLocalVmId(File file) { int lvmid = 0; try { // try 1.4.2 and later format first return Integer.parseInt(file.getName()); } catch (NumberFormatException e) { } // now try the 1.4.1 format String name = file.getName(); if (name.startsWith(dirNamePrefix)) { int first = name.indexOf('_'); int last = name.lastIndexOf('_'); try { if (first == last) { return Integer.parseInt(name.substring(first + 1)); } else { return Integer.parseInt(name.substring(first + 1, last)); } } catch (NumberFormatException e) { } } throw new IllegalArgumentException("file name does not match pattern"); }
总结
本文主要讲解了jps的使用方法及它的实现原理是什么。进一步可以思考如下一些问题:
- 这些进程对应的文件是什么时候写入对应文件夹中的?
- jps的参数是如何解析文件中的内容的?
感兴趣的同学可以继续通过阅读源码来深入了解。
- 本文由 DRFish(http://www.drfish.me/)原创,转载请写明原链接,谢谢。
- Java系统工具jps原理解析
- java jps命令使用解析
- jps原理
- java虚拟机进程状态工具------jps
- JPS 工具, 显示当前Java进程
- jps工具(查看java进程)
- Java虚拟机工具之虚拟机进程状况工具jps
- Java长期运行后, jps等工具无法连接jvm
- jps工具介绍
- jps 进程状态工具
- jvm 工具整理--jps
- JDK工具(1) jps
- jvm命令工具jps
- jdk工具--jps
- 系统标签解析原理
- JDK工具之 jps命令
- jvm工具(一)jps
- jps虚拟进程状况工具
- 6.python 相对导入
- N层交换
- python简单操作excel
- poj 1845 Sumdiv
- Flume-ng的原理和使用
- Java系统工具jps原理解析
- JAVA之旅(七)——final关键字 , 抽象类abstract,模板方法模式,接口interface,implements,特点,扩展
- 放球游戏(51nod 1418)模拟
- HTML,CSS,font-family:中文字体的英文名称 (宋体 微软雅黑)
- javaSE 模拟Spring框架的Ioc
- Matika版OpenStack伪生产环境部署-添加Compute节点
- 剑指Offer--面试题11 数值的整数次方
- Java的守护线程与非守护线程
- Access Denied: Specified user is not is not a member of TelnetClients group解决方法