Linux - 管道太多"打开文件太多",如何调试

Ale*_*eng 5 java linux ubuntu pipe

我有一个Java程序,运行大约3分钟后会抛出"打开太多文件"错误.增加打开文件限制不起作用,因为它仍然用尽所有限制,只是更慢.所以我的程序有问题,我需要找出答案.

这就是我所做的,10970是pid

  • 使用查看打开的Java进程文件,cat /proc/10970/fd找出大多数是管道
  • 使用lsof -p 10970 | grep FIFO列出所有管道,找到约450管
  • 管道看起来如下

java 10970服务1w FIFO 0,8 0t0 5890管道

java 10970服务2w FIFO 0,8 0t0 5890管道

java 10970服务169r FIFO 0,8 0t0 2450696管道

java 10970服务201r FIFO 0,8 0t0 2450708管道

但我不知道如何继续.0,8在上面的输出中表示设备编号.如何找到带有这些数字的设备?

更新

该程序是TCP服务器,从客户端和处理消息接收套接字连接.我有两个环境.在生产环境中它工作正常,但在测试环境中它最近有这个问题.在生产环境中,我没有看到这么多管道.这两个环境的代码和基础结构是相同的,都由Chef管理.

Ste*_*n C 1

但我不知道如何继续。

您需要做的是识别 Java 代码中打开这些管道的位置……并确保在使用完它们后它们始终处于关闭状态。

确保管道关闭的最佳方法是在使用完管道后显式关闭它们。例如(使用输入流而不是套接字......):

    InputStream is = new FileInputStream("somefile.txt");
    try {
         // Use file
    } finally {
         is.close();
    }
Run Code Online (Sandbox Code Playgroud)

在 Java 7 或更高版本中,您可以更简洁地编写为 ///

    try (InputStream is = new FileInputStream("somefile.txt")) {
         // Use file
    }
Run Code Online (Sandbox Code Playgroud)

在后者中,当隐式块中的...完成InputStream object时,会自动关闭。tryfinally


上面输出中的 0,8 表示设备编号。如何找到具有这些编号的设备?

这可能与解决问题无关。重点关注文件描述符没有被关闭的原因。知道设备编号的含义并没有帮助。

在生产环境中我没有看到那么多管道。

这可能也是一个转移注意力的事情。这可能是由于 GC 运行更频繁,并在出现问题之前关闭孤立的文件描述符造成的。

(但是强制GC运行并不是一个解决方案。你不应该依赖GC来关闭文件描述符。这是低效且不可靠的。)