Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用NIO非阻塞通道,不使用selector,只是channel去close,无法真正意义关闭TCP?导致小并发就挂机! #67

Open
thinkingmysky opened this issue Dec 5, 2013 · 2 comments

Comments

@thinkingmysky
Copy link

Memcache-Java-Clent3和3.X在使用nio非阻塞式管道,
但却把非阻塞式管道当作阻塞式套接字用,没有注册Selector,
JDK会注册一个临时的Selector,使用Soft引用,并使用ThreadLocal做缓存,
当线程池剧烈收缩和扩张时,就会出现很多垃圾Soft引用的Selector,
如果内存够用,这些Soft引用都不会释放,句柄数就有可能达到上限。

04:58:00,177 ERROR org.apache.tomcat.util.net.AprEndpoint Socket accept failed: org.apache.tomcat.jni.Error: Too many open files
at org.apache.tomcat.jni.Socket.__ejt_nmp_accept(Native Method) [jbossweb-7.0.13.Final.jar:]
at org.apache.tomcat.jni.Socket.accept(Socket.java) [jbossweb-7.0.13.Final.jar:]
at org.apache.tomcat.util.net.AprEndpoint$Acceptor.run(AprEndpoint.java:1136) [jbossweb-7.0.13.Final.jar:]
at java.lang.Thread.run(Thread.java:662) [rt.jar:1.6.0_45]

java 4496 root 979u sock 0,5 48421 can't identify protocol
java 4496 root 980u sock 0,5 48422 can't identify protocol
java 4496 root 981u sock 0,5 48423 can't identify protocol
java 4496 root 982u sock 0,5 48424 can't identify protocol
java 4496 root 983u sock 0,5 48425 can't identify protocol
java 4496 root 984u sock 0,5 48426 can't identify protocol
java 4496 root 985u sock 0,5 48427 can't identify protocol

但是,不知道你们是怎么解决?或者在那个版本可以解决?

对于SocketChannel和ServerSocketChannel,两者的父类是SelectableChannel,它在jdk中的文档有这么段话:

Once registered with a selector, a channel remains registered until it is deregistered.This involves deallocating whatever resources were allocated to the channel by the selector.
A channel cannot be deregistered directly; instead, the key representing its registration must be cancelled. Cancelling a key requests that the channel be deregistered during the selector's next selection operation.

也就是说关闭一个已经注册的SelectableChannel需要两个步骤:

1)取消注册的key,这个可以通过SelectionKey.cancel方法,也可以通过SelectableChannel.close方法,或者中断阻塞在该channel上的IO操作的线程来做到。
2)后续的Selector.selectXXX方法的调用才真正地关闭 本地Socket。
因而,如果,如果在取消SelectionKey后没有调用到selector的select方法(因为Client一般在取消key后, 我们都会终止调用select的循环,当然,server关闭一个注册的channel我们是不会终止select循环的),那么本地socket将进入CLOSE-WAIT 状态(等待本地Socket关闭)。简单的解决办法是在 SelectableChannel.close方法之后调用Selector.selectNow方法,类似:
Selector sel;
SocketChannel sch;
// …
sch.close();
sel.selectNow();

// .........

@mengli
Copy link
Collaborator

mengli commented Apr 3, 2014

Hi thinkingmysky,

Could you please tell us what protocol you use? TCP or UDP? ASCII or Binary protocol? Besides, could you please provide us some test code you use?

Meng

@xiaolu6t
Copy link

为什么要关闭?你要设置Pool的大小啊.不关闭就是为了效率.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants