Mac OSX上的Java进程不会释放套接字

我经常遇到一个奇怪的问题(实际上经常)。

我正在运行一个服务器应用程序,它为自己绑定一个套接字。

但偶尔,套接字不会被释放。 尽管Eclipse报告Terminate失败,但该过程终止,但它从’ps’和JConsole / JVisualVM正确消失。 ‘lsof’也不再为港口显示任何内容。 但是,当我尝试再次启动服务器到同一端口时,我收到此错误:

Caused by: java.net.BindException: Address already in use at sun.nio.ch.Net.bind(Native Method) at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:126) at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59) 

这个问题在我的unit testing中是最糟糕的,它永远不会完全运行,因为这肯定会在其中一个测试之后发生(所有测试都会重新创建服务器)。

我正在运行MacOSX 10.7.3

Java(TM)SE运行时环境(版本1.6.0_31-b04-415-11M3635)Java HotSpot(TM)64位服务器VM(版本20.6-b01-415,混合模式)

我也有Parallels,而且问题看起来似乎是由Parallels网络适配器引起的,但我不确定它是否与此问题有任何关系(我已经联系了他们的支持,目前为止没有任何帮助)。

唯一有助于解决这种情况的是重启OSX。

有任何想法吗?

这是打开套接字的相关代码:

 channel = (ServerSocketChannel) ServerSocketChannel.open().configureBlocking(false); channel.socket().bind( addr, 0 ); 

它被关闭了

  channel.close(); 

但是我认为这个过程会被卡住,然后Eclipse会杀死它。

netstat -an(对于端口6007):

 tcp4 73 0 127.0.0.1.6007 127.0.0.1.51549 ESTABLISHED tcp4 0 0 127.0.0.1.51549 127.0.0.1.6007 ESTABLISHED tcp4 73 0 127.0.0.1.6007 127.0.0.1.51544 CLOSE_WAIT tcp4 0 0 127.0.0.1.6007 127.0.0.1.51543 CLOSE_WAIT tcp4 0 0 10.37.129.2.6007 *.* LISTEN tcp4 0 0 10.211.55.2.6007 *.* LISTEN tcp4 0 0 127.0.0.1.6007 *.* LISTEN tcp4 0 0 10.50.100.236.6007 *.* LISTEN 

现在,在为每个测试打开套接字后,我得到此exception(此情况下的netstat输出):

 Caused by: java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:129) at java.net.SocketInputStream.read(SocketInputStream.java:182) 

从eclipse停止进程我得到“终止失败”,但是lsof -i TCP:6007什么也没显示,’ps’找不到进程。 netstat输出没有变化……

我可以以某种方式杀死套接字而不重新启动(这有助于一点点)?

更新5.5.12:

我现在在Eclipse调试器中运行测试。 这次测试在18种方法后被卡住了。 它被困在15分钟后停止了主线程。 这是堆栈:

 Thread [main] (Suspended) FileDispatcher.preClose0(FileDescriptor) line: not available [native method] SocketDispatcher.preClose(FileDescriptor) line: 41 ServerSocketChannelImpl.implCloseSelectableChannel() line: 208 [local variables unavailable] ServerSocketChannelImpl(AbstractSelectableChannel).implCloseChannel() line: 201 ServerSocketChannelImpl(AbstractInterruptibleChannel).close() line: 97 ... 

嗯,毕竟看起来这个过程并没有被杀死 – 并且也不会死于杀死-9(我注意到进程712,也可能是710也是TestNG进程):

 $ kill -9 712 $ ps xa | grep java 700 ?? ?E 0:00.00 (java) 712 ?? ?E 0:00.00 (java) 797 s005 S+ 0:00.00 grep java 

– 编辑:10.5.12:

?上面ps输出中的E表示进程正在退出。 我没有找到任何方法来完全杀死这样一个过程而不重新启动。 其他一些应用程序也注意到了同样的问题。 找不到解决方案:

http://www.google.com/search?q=ps+process+is+exiting+osx

尝试在每次测试后用http://docs.oracle.com/javase/1.4.2/docs/api/java/net/ServerSocket.html#close ()关闭套接字,如果你还没有。

在这里只是一个黑暗的镜头,但要确保等待Selector.select()的任何线程已被唤醒,并已退出。

所以问题似乎在于JDK 6的Mac版本中Selector的实现。安装新的Oracle JDK 7u4修复了这个问题,与Selector的使用方式无关。

我也有Parallels,通常问题看起来是由Parallels网络适配器引起的……

如果这个问题没有出现在其他平台上,我会说这是一个公平的赌注。 你做了什么来排除Parallels作为罪魁祸首?

如果您认为资源未正确发布,您可以尝试在shutdownhook中执行发布。 这样至少当它关闭时,资源将被释放(尽管如果你很难杀死)

一个非常基本的shutdownhook的例子:

 public void shutDownProceedure(){ Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { /* my shutdown code here */ } }); } 

这有助于我释放以前不完全发布的资源。 我不知道这是否也适用于套接字,我认为应该这样做。

它还让我看到了以前没见过的记录