hsperfdata_$USER目录 - Java HotSpot VM性能监控数据
本文OS基于Ubuntu Server 18.04.2 LTS x86_64
JVM基于Java 1.8.0_201 Java HotSpot(TM) 64-Bit Server VMJDK早期某些特定版本可能不适用(如1.6.0_23 -b05等某些版本)
一 起因
最近生产中遇到一个奇怪现象,使用jps
命令不显示Java应用的进程,由于之前在部署Elastic Stack时提到过/tmp
目录不可写的问题,这次第一直觉还是该问题造成的,于是尝试修改/tmp
目录权限测试,发现果然如此,但是有一点没想通,我已经将Java应用的临时目录(java.io.tmpdir
)改为自定义路径了,为什么还会受影响?
于是开一个新的虚拟机(VMware,not JVM)进行测试,看看Java到底在/tmp
目录下还有什么操作,由于新的系统/tmp
目录中文件很少,启动Java应用后,很容易就发现了问题,原来是在其中生成了一个hsperfdata_$USER
格式的文件夹,里边还有一个数字名称的文件。随手ps了一下,发现该数字刚好是Java应用的进程ID,此时算是明白为什么了,一定是jps
会来读这个目录,于是顺手查了下该目录的相关资料,记录一下。
二 简介
hsperfdata_$USER
目录是Java性能监控的相关目录,更准确点说是Oracle HotSpot VM性能监控。所以如果运行Java应用程序,就会在系统默认的临时目录/tmp
下生成该文件夹,通常是以运行Java应用的当前用户名结尾,里面会包含以Java应用进程ID为名称的数据文件。
三 重现过程
3.1 /tmp目录
默认情况下,/tmp
目录所有者和所属组为root
,权限为777
,即所有人都有读写权限。出于系统安全等因素考虑,有些系统管理员会进行优化,使/tmp
目录不可写,比如将权限改为750
,或者干脆直接将其挂载为不可写的分区等。
除权限导致不可写之外,该目录所在分区已满(使用率100%),同样会造成该目录不可写,使用df -lh
命令查看使用情况。
由于很多应用默认都要往该目录下写临时文件,此时如果该目录不可写,应用运行就可能出现问题,比如Java应用。Java应用除了要往临时目录写入一些临时数据外,还包括性能监控数据,这就是我们开头所说的hsperfdata_$USER
目录,前者可以使用系统变量java.io.tmpdir
修改为其他目录,例如-Djava.io.tmpdir=/some/other/tmpdir
,但是hsperfdata_$USER
目前好像并没有方法可以修改,只能在系统临时目录下生成。
3.2 重现问题
当然,即使hsperfdata_$USER
目录无法创建,也不影响Java程序正常运行,只是无法对该JVM进行性能监控。例如,在$JAVA_HOME/bin
目录下,有很多自带的JVM性能监控的小工具,像jps
,jstat
等均无法正常运行,因为这些工具需要访问该目录下的数据。
# 1. 修改临时目录权限,让其他用户不可读写
$ sudo chmod 750 /tmp
# 2. 启动应用, 此时/tmp目录下未生成`hsperfdata_$USER`目录
$ nohup java \
-Djava.io.tmpdir=/opt/data/package/demo/tmp \
-jar hello-world-custom-0.0.1-SNAPSHOT.jar \
> /dev/null 2>&1 &
$ ps -ef |grep java
dev 1484 1 83 14:58 pts/0 00:00:11 java -Djava.io.tmpdir=/opt/data/package/demo/tmp -jar hello-world-custom-0.0.1-SNAPSHOT.jar
此时如果运行jps
命令,会报如下错误:
# 3. 执行jps命令查看Java进程
$ jps
Exception in thread "main" java.lang.NullPointerException
at sun.jvmstat.perfdata.monitor.protocol.local.LocalVmManager.activeVms(LocalVmManager.java:148)
at sun.jvmstat.perfdata.monitor.protocol.local.MonitoredHostProvider.activeVms(MonitoredHostProvider.java:150)
at sun.tools.jps.Jps.main(Jps.java:62)
而如果尝试运行jstat
命令,同样不可以正常工作,会提示找不到指定的进程ID:
$ jstat -gcutil 1484 1000 5
1484 not found
此时将/tmp
目录权限重新修改为默认值:
$ sudo chmod 777 /tmp
然后重新运行Java应用:
$ kill 1484
$ nohup java \
-Djava.io.tmpdir=/opt/data/package/demo/tmp \
-jar hello-world-custom-0.0.1-SNAPSHOT.jar \
> /dev/null 2>&1 &
重新查看:
$ ps -ef |grep java
dev 1564 1 99 15:17 pts/0 00:00:03 java -Djava.io.tmpdir=/opt/data/package/demo/tmp -jar hello-world-custom-0.0.1-SNAPSHOT.jar
$ jps
1577 Jps
1564 jar
$ jstat -gcutil 1564 1000 5
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 100.00 37.96 69.63 95.11 92.54 93 0.439 2 0.070 0.509
0.00 100.00 37.96 69.63 95.11 92.54 93 0.439 2 0.070 0.509
0.00 100.00 37.96 69.63 95.11 92.54 93 0.439 2 0.070 0.509
0.00 100.00 40.51 69.63 95.11 92.54 93 0.439 2 0.070 0.509
0.00 100.00 40.51 69.63 95.11 92.54 93 0.439 2 0.070 0.509
一切恢复正常。
需要注意的是,如果java.io.tmpdir
指向的目录不可写,那么应用就可能起不来了。该目录也是默认指向/tmp
。
四 最后
性能监控这个特性是Oracle HotSpot VM默认开启的,使用高级运行时选项-XX:+UsePerfData
控制开启。关闭的话就不会在系统临时目录生成hsperfdata_$USER
目录,可以指定-XX:-UsePerfData
选项进行关闭。由于该选项对性能基本没有影响,所以不推荐关闭该特性。这里是关于该选项的描述:
-XX:+UsePerfData
Enables the perfdata feature. This option is enabled by default to allow JVM monitoring and performance testing.
Disabling it suppresses the creation of the hsperfdata_userid directories. To disable the perfdata feature, specify -XX:-UsePerfData.
这里还有一份关于该参数选项的一个测试。
如果你也遇到以上错误,记得去排查一下/tmp
目录的权限,或者是否还有可用空间。
版权声明:知识共享署名-非商用-非衍生 (CC BY-NC-ND 3.0) 转载请注明出处