Java命令学习系列(一)— Jps


Java命令学习系列(一)— Jps

jps 位于 jdk 的 bin 目录下,其作用是显示当前系统的 java 进程情况,及其 id 号。 jps 相当于 Solaris 进程工具 ps。不像 ”pgrep java” 或 ”ps -ef grep java” ,jps 并不使用应用程序名来查找 JVM 实例。因此,它查找所有的 Java 应用程序,包括即使没有使用 java 执行体的那种(例如,定制的启动 器)。另外,jps 仅查找当前用户的 Java 进程,而不是当前系统中的所有进程。

位置

我们知道,很多 JAVA 命令都在 jdk 的 JAVA_HOME/bin/ 目录下面,jps 也不例外,它就在 bin 目录下,它是 java 自带的一个命令。

功能

jps(Java Virtual Machine Process Status Tool)是 JDK 1.5 提供的一个显示当前所有 java 进程 pid 的命令,简单实用,非常适合在 linux/unix 平台上简单察看当前 java 进程的一些简单情况。

原理

jdk 中的 jps 命令可以显示当前运行的 java 进程以及相关参数,它的实现机制如下:

java 程序在启动以后,会在 java.io.tmpdir 指定的目录下,就是临时文件夹里,生成一个类似于

hsperfdata_User 的文件夹,这个文件夹里(在 Linux 中为 /tmp/hsperfdata_{userName}/),有几个文件,名字就是 java 进程的 pid,因此列出当前运行的 java 进程,只是把这个目录里的文件名列一下而已。 至于系统的参数什么,就可以解析这几个文件获得。例如:

[root@pudding-160 hsperfdata_root]# ll
total 96
-rw------- 1 root root 32768 Jun 25 21:28 372997
-rw------- 1 root root 32768 Jun 25 21:27 49553
-rw------- 1 root root 32768 Jun 25 21:27 5032
[root@pudding-160 hsperfdata_root]# pwd
/tmp/hsperfdata_root
[root@pudding-160 hsperfdata_root]# jps
372997 ManagerMaster
49553 RunJar
5032 ManagerAgent
433884 Jps

使用

想要学习一个命令,先来看看帮助,使用 jps -help 查看帮助:

[root@pudding-160 ~]# jps -help
usage: jps [-help]
       jps [-q] [-mlvV] [<hostid>]

Definitions:
    <hostid>:      <hostname>[:<port>]

接下来,为了详细介绍这些参数,我们编写几个类,在 main 方法里写一个 while(true) 的循环,查看 java 进程情况。代码如下:

package com.JavaCommand;
/**
 * @author pudding
 */
public class JpsDemo {
    public static void main(String[] args) {
        while(true){
            System.out.println(1);
        }
    }
}

-q 只显示 pid,不显示 class 名称、jar 文件名和传递给 main 方法的参数

pudding@DESKTOP-1QCHCU4:/mnt/wsl/demo$ jps -q
4167
4312

-m 输出传递给 main 方法的参数,在嵌入式 jvm 上可能是null,在这里,在启动 main 方法的时候,我给 String[] args 传递一个参数:pudding,执行jsp -m

pudding@DESKTOP-1QCHCU4:/mnt/wsl/demo$ jps -m
7760 Jps -m
7674 JpsDemo pudding

-l 输出应用程序 main class 的完整 package 名或者应用程序的 jar 文件完整路径名:

pudding@DESKTOP-1QCHCU4:/mnt/wsl/demo$ jps -l
4517 sun.tools.jps.Jps
4167 com.JavaCommand.JpsDemo

-v 输出传递给 JVM 的参数;在这里,在启动 main 方法的时候,我给 jvm 传递一个参数:-Dfile.encoding=UTF-8,执行jps -v

pudding@DESKTOP-1QCHCU4:/mnt/wsl/demo$ jps -v
9317 JpsDemo -Dfile.encoding=UTF-8
9391 Jps -Dapplication.home=/usr/lib/jvm/java-8-openjdk-amd64 -Xms8m

PS:jps 命令有个地方很不好,似乎只能显示当前用户的 java 进程,要显示其他用户的还是只能用 unix/linux 的 ps 命令。

jps 是我最常用的 java 命令。使用 jps 可以查看当前有哪些 Java 进程处于运行状态。如果我运行了一个 web 应用(使用 tomcat、jboss、jetty 等启动)的时候,我就可以使用 jps 查看启动情况。有的时候我想知道这个应用的日志会输出到哪里,或者启动的时候使用了哪些 javaagent,那么我可以使用 jps -v 查看进程的 jvm 参数情况。

jps 失效处理

现象

ps -ef|grep java 能看到启动的 java 进程,但是用 jps 查看却不存在该进程的 id。待会儿解释过之后就能知道在该情况下,jconsole、jvisualvm 可能无法监控该进程,其他 java 自带工具也可能无法使用。

分析

jps、jconsole、jvisualvm 等工具的数据来源就是这个文件(/tmp/hsperfdata_${userName}/pid)。所以当该文件不存在或是无法读取时就会出现 jps 无法查看该进程号,jconsole 无法监控等问题

原因

  1. 磁盘读写、目录权限问题:若该用户没有权限写/tmp目录或是磁盘已满,则无法创建 /tmp/hsperfdata_${userName}/pid 文件。或该文件已经生成,但用户没有读权限

  2. 临时文件丢失,被删除或是定期清理:对于 linux 机器,一般都会存在定时任务对临时文件夹进行清理,导致 /tmp 目录被清空。这也是我第一次碰到该现象的原因。常用的可能定时删除临时目录的工具为 crontab、redhat 的 tmpwatch、ubuntu 的 tmpreaper 等等

    这个导致的现象可能会是这样,用 jconsole 监控进程,发现在某一时段后进程仍然存在,但是却没有监控信息了。

  3. java 进程信息文件存储地址被设置,不在 /tmp 目录下:上面我们在介绍时说默认会在 /tmp/hsperfdata_${userName} 目录保存进程信息,但由于以上 1、2 所述原因,可能导致该文件无法生成或是丢失,所以 java 启动时提供了参数(-Djava.io.tmpdir),可以对这个文件的位置进行设置,而 jps、jconsole 都只会从 /tmp 目录读取,而无法从设置后的目录读物信息,这是我第二次碰到该现象的原因


文章作者: Pudding
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Pudding !
  目录