JVM 的秘密花园
软件运行或者程序开发中,有时候会需要写一些临时文件,那写这些临时文件的目录在哪呢?不同的软件,不同的语言,以及不同的操作系统都有所区别。在 Java 语言的世界里,因为是跨平台的语言,而且每个人的设置并不相同,所以这对应到具体当前系统的临时文件在哪,可以通过在代码里获取环境变量。
System.getProperty("java.io.tmpdir") 来看。
这个目录除了我们可以做为临时目录外,是不是我们不写文件的时候就用不到了呢?
其实并不是。这个目录相当于 JVM 的「秘密花园」,虚拟机会在这里记录许多的信息。
例如每一个 java 的进程,都会在该临时目录下的 `hsperfdata_$USER(你自己的用户名)`目录生成一个进程ID对应的文件。
可能有人遇到这种问题,Java 程序可以正常执行,但是通过 jps 命令不能把进程给列出来。这种一般都是和 tmpdir 有关,直接查看是否有对应的写权限,磁盘是否已满。
以后你无论是执行jps 命令,还是其他监控诊断类的应用需要 attach 到JVM 的时候,如果需要提供Java 进程列表,都会从这儿读取。而且这个进程文件并不是个空文件,里面有大量的内容。
所以我们常用的 jstat 以及我们以前文章中提到的JConsole、JVisualVM、SA 等工具,都会从这个文件这里读内容,再进行展示。
文件的内容哪里来的呢?
这了支持对 JVM 的监控,虚拟机里特地开辟了一块内存,用来存放这些性能统计相关的数据,统称为 PerfData,这也是前面目录称为 hsperfdata的原因。随着 Java 进程的不断运行,那些不断变化的监控值,虚拟机一般会通过共享内存的方式将内存与这个文件进行映射。并在数据变化的时候刷新到文件。
比如我们可以通过命令来查看加载类的信息,以及像gc 的一些数据
jstat -class file:///<path>/hsperfdata/<pid> jstat -gc file:///<path>/hsperfdata/<pid>
还不过瘾,可以试试这个命令,查看更多的监控信息
jstat -J-Djstat.showUnsupported=true -snap pid
选项默认是开启的,对性能的影响基本可以忽略,如果想要关闭,可以通过-XX:-UsePerData 来操作,
这个JVM参数官方说明如下
-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.
这个文件就是我们通过外部监控工具 attach 到 JVM 的时候,读到的那些内容。
这个秘密空间,在 JVM 内部是通过 PerfMemory 的模块来统一管理的,负责创建、分配和销毁。
正常情况下JVM 退出时会把该文件同步删除,但如果异常kill 的情况,那文件会保留下来,一直留着。下次执行哪怕一个简单的 jps 等命令时,只要启动了 java 进程,都会判断下该目录下文件对应的进程是否存在,没有就会删除了。