【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关闭。
这个问题的详细情况和解决方案,就不做这里展开了,有兴趣的可以网上搜索下。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。