【netty in action】学习笔记-第一章 理解java NIO(2)

上一篇文章理解了java nio的一些个性和根本用法。本篇持续来看看java nio有哪些问题以及netty如何解决这些问题。

跨平台和兼容性问题

java nio有nio和nio2两个版本,后者只反对jdk7。而且java nio自身属于比拟low level的api,有时候会遇到在linux运行良好然而在windows上却有问题。

netty提供对立的api,你不须要关注java的版本,也不须要关注操作系统。

ByteBuffer的扩大

通过后面的示例,你能看进去java nio的ByteBuffer并不好用,比方还有本人切换读写模式。netty扩大了ByteBuffer提供更加易用的API。具体的用法在前面章节的笔记中会具体阐明。

内存透露的问题

nio有个Scattering and Gathering的概念,就是扩散读取,集中写入。


scatter(扩散)是指数据从一个channel读取到多个buffer中。比方上面的例子:

ByteBuffer header = ByteBuffer.allocate(128);ByteBuffer body = ByteBuffer.allocate(1024);ByteBuffer[] bufferArray = { header, body }channel.read(bufferArray);

read()办法依照buffer在数组中的程序将从channel中读取的数据写入到buffer,当一个buffer被写满后,channel紧接着向另一个buffer中写。

集中读的概念就是反过来,多个buffer的数据写入到同一个channel。示例如下:

ByteBuffer header = ByteBuffer.allocate(128);ByteBuffer body = ByteBuffer.allocate(1024);ByteBuffer[] bufferArray = { header, body };channel.write(bufferArray);

java nio提供了专门的接口来解决Scattering and Gathering

public interface ScatteringByteChannel extends ReadableByteChannel{    public long read(ByteBuffer[] dsts) throws IOException;    public long read(ByteBuffer[] dsts, int offset, int length) throws IOException;}public interface GatheringByteChannel extends WritableByteChannel{    public long write(ByteBuffer[] srcs) throws IOException;    public long write(ByteBuffer[] srcs, int offset, int length) throws IOException;}

比方SocketChannel就实现了这两个接口。

然而Scattering and Gathering性能会导致内存泄露,始终到Java7才解决内存泄露问题。

epoll的缺点问题

这是个驰名的bug,它会导致Selector空轮询,最终导致CPU 100%。官网宣称在JDK1.6版本的update18修复了该问题,然而直到JDK1.7版本该问题仍旧存在,只不过该BUG产生概率升高了一些而已,它并没有被基本解决。

while (true) {            int selected = selector.select();            Set<SelectedKeys> readyKeys = selector.selectedKeys();            Iterator iterator = readyKeys.iterator();            while (iterator.hasNext()) {            //do something            }        }

解决epoll bug的惟一办法是回收旧的选择器,将先前注册的通道实例转移到新创建的选择器上。而netty正是基于此办法提供的解决方案。

netty 对Selector的select操作周期进行统计,每实现一次空的select操作进行一次计数,若在某个周期内间断产生N次空轮询,则触发了epoll死循环bug。而后netty会重建Selector,判断是否是其余线程发动的重建申请,若不是则将原SocketChannel从旧的Selector上去除注册,从新注册到新的Selector上,并将原来的Selector敞开。

这个问题的详细情况和解决方案,就不做这里开展了,有趣味的能够网上搜寻下。