阿东lazy

V2

2022/12/28阅读:20主题:橙心

【JVM】JPS命令详解释

引言

JPS命令是日常开发过程中经常使用的命令。使用起来也非常简单,本节内容主要翻译Oracel官方的JPS说明,以及相关的实现原理分析,最后介绍一些JPS无法获取到JAVA进程的原因排查。

官方文档翻译

原文:jps - Java Virtual Machine Process Status Tool (oracle.com)

SYNOPSIS(简介)

jps [ options] [ hostid ]

PARAMETERS

options

Command-line options.

hostid

The host identifier of the host for which the process report should be generated. The hostid may include optional components that indicate the communications protocol, port number, and other implementation specific data.

host唯一主机标识符号,这里实际指的是操作系统管理进程必须为应用程序分配的进程号,然后再由JVM统一管理资源标识。统一资源管理可以是协议,端口号和其他特殊数据。

OPTIONS

The jps command supports a number of options that modify the output of the command. These options are subject to change or removal in the future.

jps 命令支持许多修改命令输出的选项。这些选项将来可能会更改或删除。

-q:Suppress the output of the class name, JAR file name, and arguments passed to the main method, producing only a list of local VM identifiers.

禁止输出类名、JAR 文档名和传递给“main”方法的参数,仅生成本地 VM 标识符的列表。

[zxd@localhost ~]$ jps
10635 Jps
[zxd@localhost ~]$ jps -q
10647

-m:Output the arguments passed to the main method. The output may be null for embedded JVMs.

输出传递给 main 方法的参数。对于嵌入式 JVM,输出可能为空

[root@localhost bin]# jps -m
11057 seata-server.jar
10726 nacos-server.jar --spring.config.additional-location=file:/opt/nacos/conf/ --logging.config=/opt/nacos/conf/nacos-logback.xml --server.max-http-header-size=524288 nacos.nacos
11103 Jps -m

-l:Output the full package name for the application's main class or the full path name to the application's JAR file.

输出应用程序的启动main包的完整名称或完整路径。

[root@localhost bin]# jps -l
10726 /opt/nacos/target/nacos-server.jar
15831 sun.tools.jps.Jps
15742 /opt/seata/target/seata-server.jar

-v:Output the arguments passed to the JVM.

注意小写,输出传递给 JVM 的参数。

[root@localhost bin]# jps -v
15843 Jps -Dapplication.home=/opt/jdk8 -Xms8m
10726 nacos-server.jar -Djava.ext.dirs=/opt/jdk8/jre/lib/ext:/opt/jdk8/lib/ext -Xms512m -Xmx512m -Xmn256m -Dnacos.standalone=true -Dnacos.member.list= -Xloggc:/opt/nacos/logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -Dloader.path=/opt/nacos/plugins,/opt/nacos/plugins/health,/opt/nacos/plugins/cmdb,/opt/nacos/plugins/selector -Dnacos.home=/opt/nacos
15742 seata-server.jar -Dloader.path=/opt/seata/lib -Xmx512m -Xms512m -Xmn256m -Xss512k -XX:SurvivorRatio=10 -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:MaxDirectMemorySize=1024m -XX:-OmitStackTraceInFastThrow -XX:-UseAdaptiveSizePolicy -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/seata/logs/java_heapdump.hprof -XX:+DisableExplicitGC -Xloggc:/opt/seata/logs/seata_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+UseG1GC -Dio.netty.leakDetectionLevel=advanced -Dapp.name=seata-server -Dapp.pid=15703 -Dapp.home=/opt/seata -Dbasedir=/opt/seata -Dspring.config.location=/opt/seata/conf/application.yml -Dlogging.config=/opt/seata/conf/logback-spring.xml

-V:Output the arguments passed to the JVM through the flags file (the .hotspotrc file or the file specified by the -XX:Flags=<filename> argument).

注意大写,输出通过标志文档(.hotspotrc 文档或由 -XX:Flags=<filename> 参数指定的文档)传递给 JVM 的参数。这个参数的效果从目前看来和默认的使用方式类似,并未看到实质的作用。

-J :_option_

Pass option to the java launcher called by jps. For example, -J-Xms48m sets the startup memory to 48 megabytes. It is a common convention for -J to pass options to the underlying VM executing applications written in Java.

option 传递给 jps 调用的 java 启动器。例如,**-J-Xms48m** 将启动内存设置为 48 MB。**-J** 将选项传递给执行用 Java 编写的应用进程的底层 VM 是一种常见的约定。

HOST IDENTIFIER

接下来时第二个参数,如果不指定默认为本机的JVM程序,否则看以指定对应的主机

The host identifier, or hostid is a string that indicates the target system. The syntax of the hostid string largely corresponds to the syntax of a URI:

host标识或者hostid以字符串形式显示在目标机器,_hostid_字符串的语法与URI的语法基本对应。

[protocol:][//]hostname] [:port][ /servername ]

protocol

The communications protocol. If the protocol is omitted and a hostname is not specified, the default protocol is a platform specific, optimized, local protocol. If the protocol is omitted and a hostname is specified, then the default protocol is rmi.

通信协议。如果省略 protocol 且未指定 _hostname_,则默认协议是特定于平台的本地协议。如果省略 protocol 并指定了 _hostname_则默认协议为 rmi

hostname

A hostname or IP address indicating the target host. If hostname is omitted, then the target host is the local host.

指示目标主机的主机名或 IP 地址。如果省略 _hostname_,则目标主机是本地主机。

port

The default port for communicating with the remote server. If the hostname is omitted or the protocol specifies an optimized, local protocol, then port is ignored. Otherwise, treatment of the port parameter is implementation specific. For the default rmi protocol the port indicates the port number for the rmiregistry on the remote host. If port is omitted, and protocol indicates rmi, then the default rmiregistry port (1099) is used.

用于与远程服务器通信的默认端口。如果省略 hostnameprotocol 指定了优化的本地协议,则会忽略 port_。否则,_port 参数的处理是特定于实现的。对于缺省的 rmi 协议,_port_ 指示远程主机上 rmiregistry 的端口号。如果省略 _port_,并且 protocol 表示 rmi,则使用默认的 rmiregistry 端口 (1099)。

servername

The treatment of this parameter depends on the implementation. For the optimized, local protocol, this field is ignored. For the rmi protocol, this parameter is a string representing the name of the RMI remote object on the remote host. See the -n option for the jstatd command.

此参数的处理取决于实现。对于优化的本地协议,将忽略此字段。对于 rmi 协议,此参数是一个字符串,表示远程主机上 RMI 远程对象的名称。请参阅 jstatd 命令的 -n 选项。

DESCRIPTION(描述)

The jps tool lists the instrumented HotSpot Java Virtual Machines (JVMs) on the target system. The tool is limited to reporting information on JVMs for which it has the access permissions.

JPS 的作用是列举目标JVM当前运行的所有程序,但是仅限于当前JVM接管的所有程序。

If jps is run without specifying a hostid, it will look for instrumented JVMs on the local host. If started with a hostid, it will look for JVMs on the indicated host, using the specified protocol and port.

JPS 运行的时候不是一个特别的hostid,而是会在本地运行并且检测JVM,并且看上去像是在JVM的进程李米娜,使用特殊的协议和端口。

jstatd process is assumed to be running on the target host. The jps command will report the local VM identifier, or lvmid, for each instrumented JVM found on the target system. The lvmid is typically, but not necessarily, the operating system's process identifier for the JVM process. With no options, jps will list each Java application's lvmid followed by the short form of the application's class name or jar file name. The short form of the class name or JAR file name omits the class's package information or the JAR files path information.

假设目标主机上有一个jstatd进程正在运行,JPS命令会报告当前的VM标识或者lvmid,对于在目标系统上发现的每个工具化的JVM来说,lvmid 是普遍但是必要的,由操作系统的进程标识

The jps command uses the java launcher to find the class name and arguments passed to the main method. If the target JVM is started with a custom launcher, the class name (or JAR file name) and the arguments to the main method will not be available. In this case, the jps command will output the string Unknown for the class name or JAR file name and for the arguments to the main method.

jps 命令使用 java 启动器来查找传递给 'main' 方法的类名和参数。如果目标 JVM 是使用定制启动器启动的,那幺类名(或 JAR 文档名)和 'main' 方法的参数将不可用。在这种情况下,jps 命令将输出字符串 Unknown 作为类名或 JAR 文档名以及 main 方法的参数。

The list of JVMs produced by the jps command may be limited by the permissions granted to the principal running the command. The command will only list the JVMs for which the principle has access rights as determined by operating system specific access control mechanisms.

jps 命令生成的 JVM 列表可能受到授予运行该命令的主体的权限的限制。命令将仅列出主体具有访问权限的 JVM,该访问权限由特定于操作系统的访问控制机制确定。

NOTE: This utility is unsupported and may not be available in future versions of the JDK. It is not currently available on Windows 98 and Windows ME platforms. 此实用进程在未来JDK版本中可能会不受支持,并且在部分老旧操作系统是不支持的。

OUTPUT FORMAT

The output of the jps command follows the following pattern:

_lvmid_ [ [ _classname_ | _JARfilename_ | "Unknown"] [ _arg_* ] [ _jvmarg_* ] ]  

Where all output tokens are separated by white space. An arg that includes embedded white space will introduce ambiguity when attempting to map arguments to their actual positional parameters.

其中所有输出标记都用空格分隔。包含嵌入空格的 arg 在尝试将参数映射到其实际位置参数时会引入歧义。

NOTE: You are advised not to write scripts to parse jps output since the format may change in future releases. If you choose to write scripts that parse jps output, expect to modify them for future releases of this tool.

注意:建议您不要编写脚本来解析 jps 输出,因为格式可能会在将来的版本中发生变化。如果选择编写分析 jps 输出的脚本,请为此工具的未来版本修改它们。

EXAMPLES

This section provides examples of the jps command.

下面是JPS命令使用的一些案例:

Listing the instrumented JVMs on the local host:

列出当前机器允许的JVM:

jps
18027 Java2Demo.JAR  
18032 jps  
18005 jstat  

Listing the instrumented JVMs on a remote host:

This example assumes that the jstat server and either the its internal RMI registry or a separate external rmiregistry process are running on the remote host on the default port (port 1099). It also assumes that the local host has appropriate permissions to access the remote host. This example also includes the -l option to output the long form of the class names or JAR file names.

此示例假定 jstat 服务器及其内部 RMI 注册表或单独的外部 rmiregistry 进程在远程机上的缺省端口(端口 1099)上运行。它还假定本地主机具有访问远程主机的适当权限。此示例还包括 -l 选项,用于输出类名或 JAR 文档名的长格式。

jps -l remote.domain  
3002 /opt/jdk1.7.0/demo/jfc/Java2D/Java2Demo.JAR  
2857 sun.tools.jstatd.jstatd  

Listing the instrumented JVMs on a remote host with a non-default port for the RMI registry

This example assumes that the jstatd server, with an internal RMI registry bound to port 2002, is running on the remote host. This example also uses the -m option to include the arguments passed to the main method of each of the listed Java applications.

下面是一个打印远程服务器的JVM运行情况。

此示例假定远程主机上正在运行具有绑定到端口 2002 的内部 RMI 注册表的 jstatd 服务器。此示例还使用 -m 选项来包含传递给列出的每个 Java 应用进程的 main 方法的参数

jps -m remote.domain:2002
3002 /opt/jdk1.7.0/demo/jfc/Java2D/Java2Demo.JAR  
3102 sun.tools.jstatd.jstatd -p 2002

SEE ALSO

  • java - the Java Application Launcher
  • jstat - the Java virtual machine Statistics Monitoring Tool
  • jstatd - the jstat daemon
  • rmiregistry - the Java Remote Object Registry

实现原理

jps的命令是在$JAVA_HOME/bin下面存在的,显然和每个JVM启动都有密切关系的,既然 JPS 要搜集所有JVM的信息:

[root@localhost bin]# ls /opt/jdk8/bin/
appletviewer  jarsigner       javah         jcmd      jhat   jrunscript  jvisualvm     policytool   serialver   wsimport
ControlPanel  java            javap         jconsole  jinfo  jsadebugd   keytool       rmic         servertool  xjc
extcheck      javac           javapackager  jcontrol  jjs    jstack      native2ascii  rmid         tnameserv
idlj          javadoc         java-rmi.cgi  jdb       jmap   jstat       orbd          rmiregistry  unpack200
jar           javafxpackager  javaws        jdeps     jps    jstatd      pack200       schemagen    wsgen

java程序在启动后,会在java.io.tmpdir指定的目录下的临时文件夹里,在Linux系统中会生成一个类似于hsperfdata_User(User为登录用户)的文件夹,这个文件夹里(在Linux中为/tmp/hsperfdata_{userName}/)有几个文件,名字就是java进程的pid,因此列出当前运行的java进程,只是把这个目录里的文件名列一下而已。 至于系统的参数什么,就可以解析这几个文件获得。

我们可以实际运行实验看一下:

[root@localhost tmp]# cd /tmp/hsperfdata_root/
[root@localhost hsperfdata_root]# ls
10726  15742
[root@localhost hsperfdata_root]# jps
10726 nacos-server.jar
15742 seata-server.jar
16270 Jps

我们通过进程号可以看到是可以对应上的。java.nio.file.TempFileHelper中保存着临时文件的构建逻辑,注意这里对文件夹做了一层安全加密,防止外部应用篡改。

// temporary directory location
    private static final Path tmpdir =
        Paths.get(doPrivileged(new GetPropertyAction("java.io.tmpdir")));

JPS失效处理

因为JPS需要有对应的JVM需要具备访问权限才可以查看,比如内嵌的JVM是无法利用JPS查看。所以有时候会出现用ps -ef|grep java能看到启动的java进程,但是用jps查看却不存在该进程的id。

对于这样的JPS失效场景,我们可以通过下面的一些要点排查:

  • 磁盘读写、目录权限问题 若该用户没有权限写/tmp目录或是磁盘已满,则无法创建/tmp/hsperfdata_userName/pid文件。

  • 临时文件丢失,被删除或是定期清理。比较常见的文件丢失原因可能是定时删除临时目录的工具,比如crontabredhattmpwatchubuntutmpreaper等等

    用jconsole监控进程,发现在某一时段后进程仍然存在,但是却没有监控信息了。

  • JAVA的进程信息存储被转移,JPS是无法搜集到这一类信息的,比如内嵌的JVM,此外java启动时提供了参数(-Djava.io.tmpdir)可以轻松修改进程信息启动和存储目录。但是这个设置的改变会导致JPS和Jconsole无法读取到。

杀进程

这里介绍比较常见但是实际上 完全不推荐使用的方法:

[root@localhost hsperfdata_root]# jps
10726 nacos-server.jar
16779 Jps
15742 seata-server.jar
[root@localhost hsperfdata_root]# kill -9 15742

当然 ps -ef | grep java或者使用ps -aux | grep java查找进程号,然后kill -9 进程号,这个进程号在搜索结果里面处于第二列,比如这里如果我想要kill掉dashboard,就可以使用kill -9 4002结束进程:

ps -ef | grep java 的内容:

root       4002   3942  0 14:56 pts/0    00:00:00 sh -c java $JAVA_OPTS -jar /rocketmq-dashboard.jar
root       4628   4002  0 14:56 pts/0    00:01:58 java -Drocketmq.namesrv.addr=192.168.58.128:9876 -jar /rocketmq-dashboard.jar
3000       4997   4916  0 14:56 ?        00:01:08 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/bin/java -server -Xms909M -Xmx909M -Xmn200M -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 -XX:-UseParNewGC -verbose:gc -Xloggc:/dev/shm/rmq_srv_gc.log -XX:+PrintGCDetails -XX:-OmitStackTraceInFastThrow -XX:-UseLargePages -Djava.ext.dirs=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre/lib/ext:/home/rocketmq/rocketmq-4.9.4/bin/../lib -cp .:/home/rocketmq/rocketmq-4.9.4/bin/../conf: org.apache.rocketmq.namesrv.NamesrvStartup
root      10726      1  0 15:44 pts/0    00:04:14 /opt/jdk8/bin/java -Djava.ext.dirs=/opt/jdk8/jre/lib/ext:/opt/jdk8/lib/ext -Xms512m -Xmx512m -Xmn256m -Dnacos.standalone=true -Dnacos.member.list= -Xloggc:/opt/nacos/logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -Dloader.path=/opt/nacos/plugins,/opt/nacos/plugins/health,/opt/nacos/plugins/cmdb,/opt/nacos/plugins/selector -Dnacos.home=/opt/nacos -jar /opt/nacos/target/nacos-server.jar --spring.config.additional-location=file:/opt/nacos/conf/ --logging.config=/opt/nacos/conf/nacos-logback.xml --server.max-http-header-size=524288 nacos.nacos
3000      15416  15395  3 16:05 ?        00:16:22 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/bin/java -server -Xms909M -Xmx909M -Xmn200M -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m -XX:-OmitStackTraceInFastThrow -XX:+AlwaysPreTouch -XX:MaxDirectMemorySize=909M -XX:-UseLargePages -XX:-UseBiasedLocking -Djava.ext.dirs=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre/lib/ext:/home/rocketmq/rocketmq-4.9.4/bin/../lib -cp .:/home/rocketmq/rocketmq-4.9.4/bin/../conf: org.apache.rocketmq.broker.BrokerStartup -c ../conf/broker.conf
root      16809  10683  0 22:56 pts/0    00:00:00 grep --color=auto java

ps -aux | grep java 的内容:

root       4002  0.0  0.0   4324     8 pts/0    Ss+  14:56   0:00 sh -c java $JAVA_OPTS -jar /rocketmq-dashboard.jar
root       4628  0.4  6.8 2983732 128476 pts/0  Sl+  14:56   1:58 java -Drocketmq.namesrv.addr=192.168.58.128:9876 -jar /rocketmq-dashboard.jar
3000       4997  0.2  7.5 3445320 141516 ?      Sl   14:56   1:08 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/bin/java -server -Xms909M -Xmx909M -Xmn200M -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+CMSClassUnloadingEnabled -XX:SurvivorRatio=8 -XX:-UseParNewGC -verbose:gc -Xloggc:/dev/shm/rmq_srv_gc.log -XX:+PrintGCDetails -XX:-OmitStackTraceInFastThrow -XX:-UseLargePages -Djava.ext.dirs=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre/lib/ext:/home/rocketmq/rocketmq-4.9.4/bin/../lib -cp .:/home/rocketmq/rocketmq-4.9.4/bin/../conf: org.apache.rocketmq.namesrv.NamesrvStartup
root      10726  0.9 27.1 3533976 506316 pts/0  Sl   15:44   4:15 /opt/jdk8/bin/java -Djava.ext.dirs=/opt/jdk8/jre/lib/ext:/opt/jdk8/lib/ext -Xms512m -Xmx512m -Xmn256m -Dnacos.standalone=true -Dnacos.member.list= -Xloggc:/opt/nacos/logs/nacos_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -Dloader.path=/opt/nacos/plugins,/opt/nacos/plugins/health,/opt/nacos/plugins/cmdb,/opt/nacos/plugins/selector -Dnacos.home=/opt/nacos -jar /opt/nacos/target/nacos-server.jar --spring.config.additional-location=file:/opt/nacos/conf/ --logging.config=/opt/nacos/conf/nacos-logback.xml --server.max-http-header-size=524288 nacos.nacos
3000      15416  3.9 17.3 5065612 322680 ?      Sl   16:05  16:31 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/bin/java -server -Xms909M -Xmx909M -Xmn200M -XX:+UseG1GC -XX:G1HeapRegionSize=16m -XX:G1ReservePercent=25 -XX:InitiatingHeapOccupancyPercent=30 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=8 -verbose:gc -Xloggc:/dev/shm/mq_gc_%p.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintAdaptiveSizePolicy -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=30m -XX:-OmitStackTraceInFastThrow -XX:+AlwaysPreTouch -XX:MaxDirectMemorySize=909M -XX:-UseLargePages -XX:-UseBiasedLocking -Djava.ext.dirs=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.332.b09-1.el7_9.x86_64/jre/lib/ext:/home/rocketmq/rocketmq-4.9.4/bin/../lib -cp .:/home/rocketmq/rocketmq-4.9.4/bin/../conf: org.apache.rocketmq.broker.BrokerStartup -c ../conf/broker.conf
root      16817  0.0  0.0 112816   980 pts/0    S+   23:00   0:00 grep --color=auto java

写在最后

JPS总体上是一些其他JVM工具的引导,比如Jstat需要依赖JPS获取的进程号进行性能优化和问题排查,JConsole工具来监控JVM的运行情况。

分类:

后端

标签:

Java

作者介绍

阿东lazy
V2

摸鱼JAVA工程师 公众号:懒时小窝