未关闭java.nio.channels.SocketChannel可导致Too many open files

在调用静态open方法创建java.nio.channels.SocketChannel对象后,必须调用close方法关闭SocketChannel对象以释放创建的文件句柄(fd)资源,否则如果不断地创建SocketChannel对象会使得打开文件的句柄数达到系统设定的上限,从而出现 “Too many open files”的问题。
现象:1)通过netstat -n | wc -l 查看连接数并不多; 2)系统或jvm报Too many open files; 3)通过命令ls -l /proc/<pid>/fd | grep socket |wc -l 查看有大量与socket关联的文件句柄。
原因分析:
下面是java.nio.channels.SocketChannel的open方法,该方法调用SelectorProvider.provider().openSocketChannel()创建SocketChannel对象。
public static SocketChannel open() throws IOException {
return SelectorProvider.provider().openSocketChannel();
}
我们先看SelectorProvider.provider()返回的对象。如果没有提供自定义的SelectorProvider实现,SelectorProvider.provider()会返回sun.nio.ch.DefaultSelectorProvider.create()创建的SelectorProvider对象,在linux下是sun.nio.ch.EPollSelectorProvider。
sun.nio.ch.EPollSelectorProvider的openSocketChannel()方法继承了sun.nio.ch.SelectorProviderImpl的实现,而sun.nio.ch.SelectorProviderImpl的openSocketChannel()直接返回创建的sun.nio.ch.SocketChannelImpl对象,其构造函数如下:
SocketChannelImpl(SelectorProvider sp) throws IOException {
super(sp);
this.fd = Net.socket(true);
this.fdVal = IOUtil.fdVal(fd);
this.state = ST_UNCONNECTED;
}

sun.nio.ch.Net.socket(boolean stream)的实现如下:
static FileDescriptor socket(boolean stream) {
return IOUtil.newFD(socket0(stream, false));
}
IOUtil.newFD的实现如下
static FileDescriptor newFD(int i) {
FileDescriptor fd = new FileDescriptor();
setfdVal(fd, i);
return fd;
}
可见,在创建SocketChannelImpl对象时创建了一个文件句柄,尽管这个文件句柄尚未和socket绑定,但已经开始占用系统的fd资源。所以在使用SocketChannel后一定要调用close()方法,尤其是在创建socket时出现异常时,一定要调用SocketChannel.close()方法将fd资源关闭/释放,否则就会出现上面的现象连接数不高,但文件句柄数很高。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值