Java NIO 导致文件描述符泄漏问题

4
我们有一个基于Java NIO实现的HTTP服务器。 它运行在Ubuntu 10.04.2 LTS上,使用的是Java版本“1.6.0_20”。 Java(TM) SE Runtime Environment (build 1.6.0_20-b02) Java HotSpot(TM) Server VM (build 16.3-b01, mixed mode)
然而,它泄漏了文件描述符,这些文件描述符都是Unix域套接字。
当我们使用命令"netstat -anp"时,我们发现该进程只打开了两个Unix域套接字。但是,当我们使用"lsof -p"命令时,我们会发现有大量的文件描述符,它们都是Unix域套接字,并且与在netstat中找到的那个具有相同的设备值和节点值。
我已经检查了我们的代码,所有的SocketChannels都被正确关闭了。
这是Sun JDK的一个bug吗?我们应该如何修复它?

你尝试过Java 6更新26吗?如果这是JVM的一个bug,有可能已经被修复了,这将表明它确实是一个bug。 - Peter Lawrey
@James 你正在使用哪个NIO API来使用Java与Unix域套接字?你是否使用特定的API,如XNIO?我正在寻找适用于Unix域套接字和NIO的API。谢谢。 - jbx
2个回答

3
找到了根本原因。 在我们的代码中,当我们关闭 socketchannel 时,我们也会取消 key。问题是: a. 我们在选择线程中取消 key,在另一个线程中关闭 socketchannel b. 直到调用 key.cancel,socket channel 才会被关闭。
通过阅读 close 和 cancel 的实现,我们可以发现 unix 域套接字是通过 dup2 打开的,并且有时没有被关闭(并发问题)。

关闭通道会取消键:您不需要自己再次取消。我不知道“调用key.cancel将关闭套接字通道”的意思,但如所述是错误的。实际发生的是,直到下一次选择器运行之前,该通道才不会真正关闭。 - user207421
如果在选择器线程之外的线程中执行以下代码,它也会出现问题。 selectionKey.cancel(); socketChannel.close();在我们的代码中,有点不同。在选择器线程中调用了selectionKey.cancel,并通知另一个线程调用socketChannel.close();。它也存在并发问题,因为实际上键是在下一次选择时被取消的。 - James
嗨EJP,我们遇到的问题是即使下一次选择器运行,由于并发问题,Unix域套接字也不会关闭。实际上,如果发生并发问题,Unix域套接字将没有关闭的机会。 - James
在我们的代码中,有些不同。selectionKey.cancel在选择器线程中被调用,并且它通知另一个线程调用socketChannel.close()。为什么?为什么不直接在选择器线程中关闭通道?在取消密钥后,它已经没有太多用处了。至于之前的回复,你可以将其简化为socketChannel.close(),并且其执行效果是相同的。 - user207421

0

我相信选择器使用Unix域套接字。你有关闭它们吗?


我们只创建一个 Selector 实例并且从不关闭它。 - James

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接