【问题分析】打开的文件过多

背景

系统上线运行一段时间之后突然崩溃,重启后正常运行,过一段时间后再次崩溃。查看系统日志发现,原因是open too many files,打开的文件过多
先紧急处理一下,输入命令ulimt -a,查看系统给进程分配的最大的文件打开数。

core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 29896
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 29896
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

可以看到open files的值是1024,表示单个进程最多只能打开1024个文件(也可使用ulimit -n直接查看)。那就先把这个值调大,为分析原因争取时间。

vim /etc/security/limits.conf
# 在文件尾部写入配置
* - nofile 65535

问题分析

系统除了打开依赖的jar包以及日志等文件以外,就是业务需要打开一些EXCEL和PDF模板,初步猜测可能是业务打开了这些模板之后没有关闭,时间长了就到了open files阈值。

测试

在测试环境上部署,测试那些需要使用EXCEL和PDF模板的业务,并在LINUX中监控打开的文件。

# 查看进程号
jps -l
# 打印PID进程打开的文件,按照第9列(文件名)排序展示
lsof -p PID | sort -k9

每次操作完之后都执行上述命令查看打开的文件,然后发现PDF文件每次打开了都不会关闭,越积累越多。

解决

最后定位到调用模板填充PDF这个公共方法,其中PdfReader对象使用完未关闭可能是根本原因。
修改代码后再次测试,问题解决。

	/**
     * 根据模板填充PDF
     */
    public static void templetTicket(Object model,String templatePdfPath,String targetPdfpath) throws Exception {
    	// PdfReader 需要关闭
        PdfReader reader = new PdfReader(templatePdfPath);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        PdfStamper ps = new PdfStamper(reader, bos);
        FileOutputStream fos = new FileOutputStream(targetPdfpath);
        try {
			// 省略代码...
        } catch (Exception e) {
            throw e;
        }finally {
            ps.close();
            fos.close();
            bos.close();
            // 关闭 PdfReader
            reader.close();
        }
    }
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐