Netty巧妙的规避了JDK在linux中NIO的epoll的空轮询Bug

61 篇文章 3 订阅
1 篇文章 0 订阅

一、NIO的空轮询bug描述

JDK1.5开始引入了epoll基于事件响应机制来优化NIO。相较于select和poll机制来说,epoll机制将事件处理交给了操作系统内核(操作系统硬中断)来处理,优化了elect和poll模型的无效遍历问题。

 但是JDK中epoll的实现却是有漏洞的,其中最有名的就是NIO空轮询bug(该bug只存在于Linux,因为Linux中NIO底层是使用epoll实现的,而Windows不是)。
理论上无客户端连接时Selector.select() 方法会阻塞,但空轮询bug导致:即使无客户端连接,NIO照样不断的从select本应该阻塞的Selector.select()中wake up出来,导致CPU100%问题。,如下图所示:

如上图所示,NIO程序一直处于while死循环中,不断向cpu申请资源导致CPU 100%! 官方声称在JDK1.6版本的update18修复了该问题,但是直到JDK1.7、JDK1.8版本该问题仍旧存在,只不过该BUG发生概率降低了一些而已,它并没有被根本解决。 

二、Netty中的解决应对方法

Netty规避了JDK的空轮询Bug。具体怎么做的呢,我们来看源码。

1、selector.select(timeoutMillis)
调用了select方法,并默认设置1秒超时时间,同时记录轮询次数:selectCnt ++;

在这里插入图片描述

2、获取当前时间,计算select方法的操作时间是否真的阻塞了timeoutMillis:
如果是,就证明是一次正常的select(),重置selectCnt = 1;
如果不是,可能触发了JDK的空轮询BUG,然后判断selectCnt 轮询次数是否大于默认的512(大于这个阈值就直接被netty判定认为是空轮询bug了,即使有可能误伤也不惯毛病!),然后进行rebuildSelector()。

在这里插入图片描述

3、rebuildSelector()方法重新打开一个Selector(新建了一个线程);
然后遍历oldSelector,将所有的key重新注册()到新的Selector;
然后重新赋值selector,selectCnt = 1;这时候已经规避了空轮询(因为空轮询bug出现是小概率事件,所以bug出现了,就新建一次select临时避免一下就可以了
成员变量this.selector 指向新的Selector的引用。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

 


转载参考自,对原文有内容增加:

(44 封私信 / 84 条消息) Netty 解决/规避了JDK的NIO bug了吗? - 知乎 (zhihu.com)icon-default.png?t=M276https://www.zhihu.com/question/291370310(180条消息) NIO的空轮询bug是什么?netty是如何解决NIO空轮询bug的?_李哈ha的博客-CSDN博客_netty解决了nio什么问题​​​​​​icon-default.png?t=M276https://blog.csdn.net/qq_43049310/article/details/113688981 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值