共计 1941 个字符,预计需要花费 5 分钟才能阅读完成。
【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 敞开。
这个问题的详细情况和解决方案,就不做这里开展了,有趣味的能够网上搜寻下。