Linux – 用pipe道“打开的文件太多”,如何debugging

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

这是我做的, 10970是pid

  • 使用cat /proc/10970/fd检查Java进程的打开文件,并找出其中大部分是pipe道
  • 使用lsof -p 10970 | grep FIFO lsof -p 10970 | grep FIFO列出所有pipe道并find大约450个pipe道
  • pipe道看起来像下面

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

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

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

Java 10970服务201r FIFO 0,8 0t0 2450708pipe道

但是我不知道如何继续。 上面输出中的0,8表示器件编号。 我怎样才能find这些数字的设备?

更新

该程序是一个TCP服务器,并从客户端接收套接字连接并处理消息。 我有两个环境。 在生产环境中工作正常,但在testing环境中最近有这个问题。 在生产环境中,我看不到这么多的pipe道。 这两个环境的代码和基础设施是相同的,都由厨师pipe理。

但是我不知道如何继续。

你需要做的是在你打开这些管道的地方确定你的Java代码的位置或地方,并确保它们在你完成之后总是关闭的。

确保管道关闭的最好方法是在完成管道时明确关闭管道。 例如(使用输入流而不是套接字…):

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

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

  try (InputStream is = new FileInputStream("somefile.txt")) { // Use file } 

在后者中,当try在一个隐式的finally块中完成时, InputStream object会自动关闭。


上面输出中的0,8表示器件编号。 我怎样才能找到这些数字的设备?

这可能与解决问题无关。 重点关注为什么文件描述符没有被关闭。 知道什么设备号码意味着没有帮助。

在生产环境中,我看不到这么多的管道。

这可能也是一个红鲱鱼。 这可能是由于GC更频繁地运行造成的,在成为问题之前关闭孤立的文件描述符。

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