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

Mac OSX上的Java进程不释放套接字,java,eclipse,macos,parallels,Java,Eclipse,Macos,Parallels,我时不时会遇到一个奇怪的问题(事实上太经常了) 我正在运行一个服务器应用程序,它正在为自己绑定一个套接字 但有时,插座不会释放。尽管Eclipse报告Terminate失败,但该进程将终止,但它将从“ps”和JConsole/JVisualVM中正确消失lsof'也不再显示端口的任何内容。但是,当我再次尝试将服务器启动到同一端口时,仍然会出现以下错误: Caused by: java.net.BindException: Address already in use at sun.nio

我时不时会遇到一个奇怪的问题(事实上太经常了)

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

但有时,插座不会释放。尽管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)
在我的单元测试中,问题最严重,它从未完全运行,因为这肯定会在其中一个测试之后发生(所有测试都重新创建了服务器)

我正在运行MacOSX 10.7.3

Java(TM)SE运行时环境(构建1.6.0_31-b04-415-11M3635) Java HotSpot(TM)64位服务器虚拟机(构建20.6-b01-415,混合模式)

我也有Parallels,通常问题看起来像是由Parallels网络适配器引起的,但我不确定这到底是否与此问题有关(到目前为止,我已经联系了他们的支持人员,但没有任何帮助)

唯一有助于解决这种情况的方法是重新启动OSX

有什么想法吗

--

这是打开插座的相关代码:

channel = (ServerSocketChannel) ServerSocketChannel.open().configureBlocking(false);
 channel.socket().bind( addr, 0 );
它就在附近

  channel.close();
但是我假设这个过程在这里被卡住了,然后Eclipse将其终止

--

netstat-an(用于端口6007):

--

现在,在为每个测试打开套接字之后,我都会得到这个异常(这种情况下的netstat输出):

--

从eclipse停止进程时,我得到“Terminate failed”,但是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进程):

-- 编辑:10.5.12:

?上述ps输出中的E表示该过程正在退出。我无法找到任何方法在不重新启动的情况下完全终止这样一个进程。其他一些应用程序也注意到了同样的问题。未找到解决方案:


尝试用 () 每次测试后,在拆卸过程中,如果您还没有完成

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


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

如果你认为资源没有被正确释放,你可以尝试在关闭钩子中释放。这样至少当它关闭时,资源会被释放(如果你硬杀掉的话就不会了)

一个非常基本的关闭挂钩示例:

public void shutDownProceedure(){
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            /* my shutdown code here */
        }
    });
}
这帮助我释放了以前没有完全释放的资源。我不知道这是否也适用于套接字,我认为应该


它还允许我查看以前从未见过的日志,这只是一个暗中操作,但请确保等待Selector.select()的所有线程都已被唤醒并退出。

因此,问题似乎在于JDK 6 Mac版本中Selector的实现。安装新的Oracle JDK 7u4修复了该问题,与选择器的使用方式无关。

在测试中,是否重复绑定和解除绑定到套接字?如果你这么做很快,可能你遇到了一些对时间敏感的错误。你能显示你创建和绑定套接字的代码以及你设置的任何选项吗?在测试失败后立即运行
netstat-an
,看看套接字是否处于
TIME\u WAIT
状态。正如其他人所说,请输入更多代码。这将有助于确定这是一个编程问题,还是您正面临与套接字生命周期相关的其他问题。问题:当应用程序试图被TestNG关闭时,您能否发布一个线程转储,说明它是什么样子的?这里只是一个简单的说明,但是您是否也可以确保等待
Selector.select()
的任何线程都已被唤醒并退出?请参阅我对该问题的新评论。当服务器关闭时,为每个测试创建的服务器对象应关闭套接字。是否在“channel.close()”上检查异常?是的,但它们已被吃掉。我现在在调试器中运行测试,在catch子句中设置了断点。事实证明,服务器终结时曾发生一次错误,导致无法调用close。但是,TestNG(我正在使用)停止了这个过程,套接字再次处于保留状态,我必须为测试分配一个新的套接字才能再次运行。在Windows中,我从来没有遇到过这样的问题,即无论测试如何失败,它们都会阻止套接字再次使用。下一次运行(使用新套接字)在客户端尝试访问套接字时再次遇到SocketTimeoutException:Read超时。现在所有的测试都因为同样的原因暂停了。调试器没有在channel.close()中的catch子句处停止,也没有记录任何错误(我也在那里添加了日志记录)…在第14个测试方法(套件中有几百个)之后,下一次使用新套接字运行时也会出现相同的结果。是的,问得好。我还没有能够禁用Parallels网络接口,因为如果VM被挂起或停止,它似乎仍然会保留接口。我需要再试一次——不知何故,我得到的印象是,它可能根本不会影响它。另外,我刚才在编辑中添加的内容给人的印象是,这是一个“常见”的OSX问题。@jouniaro,无法解决的退出过程是
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  
...
$ 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
public void shutDownProceedure(){
    Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            /* my shutdown code here */
        }
    });
}