JDK NIO 空轮询的bug 及Netty的解决方案

271 阅读1分钟

JDK NIO的空轮询BUG其实是JDK NIO在Linux系统下的epoll空轮询问题

epoll 是Linux下一种高效的IO复用方式,相较于传统的select和poll机制来说,epoll机制将事件处理交给了操作系统内核来处理,优化了select和poll模型的无效遍历问题。

但是JDK中的epoll的实现却是有漏洞的,这就是著名的NIO空轮询的bug。理论上无客户端连接时,Selector.select()方法会阻塞,但现实却是:即使无客户端连接,NIO照样从本该阻塞的Selector.select()中wake up出来,导致CPU飙升的问题,如下图所示:

image.png

NIO程序一直处于while死循环中,不断向CPU申请资源导致CPU 100%,直到JDK1.8该问题仍旧存在。

Netty 如何解决NIO空轮询的bug

虽然netty底层是对NIO的高度封装,但netty并没有空轮询导致cpu 100%的情况,那么netty是怎么做的呢?进入netty的select源码可以看到,netty底层也是调用NIO的selector方法,但netty用selectCnt来记录轮询次数。

image.png

selectCnt 在正常逻辑时,会被重新赋值为1,在出现空轮询bug时会累加,直到大于阈值512,则触发重构selector操作。从这里可以看到netty并没有真正解决NIO的epoll模型的bug,而是采用替换selector的操作巧妙的避开了空轮询bug。

image.png