JDK NIO的epoll bug,会导致Selector空轮询,最终导致CPU 100%
Bug出现的原因
若Selector的轮询结果一直为空,没有新消息处理,则发生空轮询,CPU使用率100%(在selector中,即使是select轮询事件为0的话,照样不断的从select本应该阻塞状态下wake up出来)
Netty的解决方案
- 对
Selector的select操作周期进行统计,每完成一次空的select操作进行一次计数 - 若在某个周期内连续发生N次空轮询,则触发了
epoll死循环bug。 - 重建
Selector,将出现bug的Selector上的channel重新注册到新的Selector上,并将原来的Selector关闭,使用新的Selector进行替换。
JDK源码分析:
JDK NIO执行代码如下:

执行selector.select()方法返回keys是0,所以本应该对key值进行遍历的事件处理根本没有执行,又回到最上面的while(true)循环,循环往复,不断的轮询,直到系统出现100%的CPU情况,最终导致程序崩溃。
Netty源码分析
具体位置在实现类NioEventLoop中:

netty会在每次进行 selector.select(timeoutMillis) 之前记录一下开始时间currentTimeNanos,在select之后记录一下结束时间,判断select操作是否至少持续了timeoutMillis时间;selectCnt记录空轮询次数
重建selector
当发生epoll bug,则创建一个新的Selector,将出现bug的Selector上的channel重新注册到新的Selector上,关闭bug的Selector,使用新的Selector进行替换 :

Netty的解决策略:
- 根据该
bug的特征,首先侦测该bug是否发生 - 将问题
Selector上注册的Channel转移到新建的Selector上 - 老的问题
Selector关闭,使用新建的Selector替换






