首页 > 解决方案 > java 进程创建处于已删除状态但增加了 linux VM 中的磁盘利用率的 tmp/tmp* 文件

问题描述

我有一个 java spring boot 应用程序,它实现了多线程,其中一个线程订阅 ZMQ,四个并行线程根据一些预定的时间间隔对接收到的数据执行一些处理。当 jar 在 linux VM 上运行并使用命令检查打开的文件时

lsof -s -p<pid>

它显示了一个“tmp/tmp* ... (deleted)”类型的文件,其磁盘利用率呈指数增长,并且进程树显示该文件属于正在运行的 java 进程。此问题仅在 linux VM 环境中遇到,在 linux 主机上不会遇到。

应用程序代码没有任何这样的情况,即文件被删除而不关闭。下面是使用文件处理的代码片段:

File file = null;
        PrintWriter printWriter = null;
        BufferedReader br = null;
        FileReader fileReader = null;
        FileWriter fileTruncateObject = null;
try {
                    file = new File(filePath);
                    printWriter = new PrintWriter(file);
                    for (T obj : list) {

                        String jsonString = writeJsonString(obj);
                        if ((jsonString.getBytes().length + file.length()) < 123) {
                            printWriter.write(jsonString);
                            printWriter.flush();

                        }

                        if ((jsonString.getBytes().length + file.length() >= 123) {
                            printWriter.close();
                            fileReader = new FileReader(file);
                            br = new BufferedReader(fileReader);
                            String data = br.readLine();
                            // do something with data
                            br.close();
                            fileReader.close();
                            // file reading successfull, now truncating the file and opening new printwriter object!
                            fileTruncateObject = new FileWriter(file, true);
                            fileTruncateObject.close();
                            printWriter = new PrintWriter(file);
                        }

                    }
                } finally {
                    if (printWriter != null) {
                        printWriter.close();
                    }
                    if (br != null) {
                        try {
                            br.close();
                        } catch (IOException e) {

                        }
                    }
                    if (fileReader != null) {
                        try {
                            fileReader.close();
                        } catch (IOException e) {

                        }
                    }
                    if (file.exists()) {
                        try {
                            if (file.delete()) {
                                //
                            }
                        } catch (Exception e) {
                        }
                    }
                }

此外,该应用程序使用TimeBasedRollingPolicy的最大大小为 10 MB,最大历史记录为 15 天,具有以下属性:

logging.pattern.console= %d{yyyy-MMM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{15} - %msg%n
logging.pattern.file= %d{yyyy-MMM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{15} - %msg%n
logging.level.com.*=DEBUG
logging.path=logs
logging.file=${logging.path}//a.%d.log
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.RollingPolicy=org.apache.log4j.rolling.TimeBasedRollingPolicy
logging.file.max-size=10MB
logging.file.max-history=15 

我无法读取文件的内容,因为它处于已删除阶段。此外,它针对“2u”文件描述符。可能在写入文件的过程中发生了一些错误,/tmp但我怎么知道错误是什么以及这些错误背后的原因是什么?有什么办法可以避免创建这个/tmp文件,或者有没有办法读取这个文件的内容?

标签: javalinuxmultithreadingspring-boot

解决方案


用于在 linux VM 中运行 java 进程的命令涉及标准输出的“nohup”和“tee”。有问题的 /tmp/ 中的输出取决于进程接收到的数据(非常庞大),因此日志开始打印在 /tmp/ 以及属性文件中配置的日志目录中。简单地重定向java进程的stdout和stderr就解决了这个问题。

正确命令示例:

nohup java jar <jar name> 2>&1 > dev/null &


推荐阅读