2011-08-12 79 views
2

我們有一個基於Java NIO實現的http服務器。 它運行在Java版本爲「1.6.0_20」的Ubuntu 10.04.2 LTS上。運行環境(build 1.6.0_20-b02) Java HotSpot™服務器虛擬機(內部版本16.3-b01,混合模式)Java NIO導致文件描述符泄漏

但是,它泄漏文件描述符,它們都是unix域套接字。

當使用命令「netstat -anp」時,我們可以發現該進程只打開兩個unix域套接字。 但是,使用lsof -p時,我們可以發現有大量文件描述符是unix域套接字,並且具有與在netstat中找到的相同的設備值和節點值。

我檢查了我們的代碼,並且所有的SocketChannel都正常關閉。

這是Sun JDK的bug嗎? 我們該如何解決它?

+0

你有沒有試過Java 6 update 26?如果它是一個JVM錯誤,它可能已被修復,這將顯示它是一個錯誤。 –

+0

@James您使用哪種NIO API將Java與Unix域套接字一起使用?你是否使用了像XNIO這樣的特定API?我正在尋找能夠與Unix Domain Sockets和NIO一起工作的東西。謝謝。 – jbx

回答

2

找到了根本原因。 在我們的代碼中,當我們關閉socketchannel時,我們也取消了密鑰。問題是: a。我們取消了選擇線程中的密鑰,並關閉了另一個線程中的套接字通道 b。套接字通道關閉,直到key.cancel被調用。

通過閱讀關閉和取消的實現,我們可以發現unix域套接字是由dup2打開的,並且從未關閉過幾次(併發問題)。

+0

關閉頻道將取消密鑰:您也不需要自行取消。我不知道什麼'套接字通道被關閉,直到key.cancel被調用'意在表示,但如前所述它是錯誤的。實際上發生的事情是,直到下一次選擇器運行時,通道* isnt'*才真正關閉。 – EJP

+0

如果下面的代碼在選擇器線程以外的線程中執行,它也會有問題。 'selectionKey.cancel(); socketChannel.close();' 在我們的代碼中,它有點不同。 selectionKey.cancel在選擇器線程中調用,並通知另一個線程調用'socketChannel.close();'。它也具有併發問題,因爲在下一次選擇時實際上取消了密鑰。 – James

+0

嗨EJP,我們遇到的問題是,即使下次選擇器運行,由於併發問題,unix域套接字未關閉。實際上,如果發生併發問題,unix域套接字將沒有機會關閉。 – James

0

我相信Selectors使用Unix域套接字。你正在關閉它們嗎?

+0

我們只創建一個Selector實例並且永遠不關閉它。 – James