第八章 - IoBuffer
IoBuffer是MINA应用程序中使用的字节缓冲区(ByteBuffer)
IoBuffer是NIO的ByteBuffer的替代品。MINA没有直接使用NIO的ByteBuffer,因为以下原因:
ByteBuffer缺少一些有用的getter和putter方法,例如fill, get/putString,和get/putAsciiInt().
ByteBuffer是固定长度的,所以很难写入变长数据。
在MINA3中IoBuffer会发生变化。MINA在NIO的ByteBuffer之上又做了一层包装的主要原因是想要一个可以扩展的Buffer。 这是个非常糟糕的决定。Buffer就是Buffer:一个在数据被使用之前的临时存放数据的地方。如果仅仅是希望扩展的话其实还有很多其他的方案,例如利用一个NIO的ByteBuffer的列表来实现,而不是把既存的数据复制到更大的Buffer中。
在所有的过滤器中使用InputStream而非ByteBuffer可能更好,因为InputStream不代表任何数据类型,它的源头可以是一个字节数组,字符串,或其他消息对象。。。
并且,现在的实现方式不能满足Buffer的一个重要目标:零拷贝(一旦我们从socket把数据读到Buffer,就不要再从Buffer复制到其他地方)。因为我们使用可扩展的字节缓冲区,所以当数据大于我们预定义的缓冲区大小时,数据就会被复制到更大的缓冲区。因为MINA的ByteBuffer只是NIO的ByteBuffer的一个包装,当使用的是直接缓冲区时就会产生很大的问题了。
IoBuffer的操作
分配一个新的Buffer。
IoBuffer是一个抽象类,所以你不能直接初始化一个IoBuffer。为了分配一个IoBuffer,我们需要使用两个allocate()方法。
// 通过指定大小和类型(direct 或 heap)来分配一个新的Buffer
public static IoBuffer allocate(int capacity, boolean direct)
// 通过指定大小来分配Buffer。
public static IoBuffer allocate(int capacity)
allocate()方法需要1个或2个参数。两个参数如下 :
capacity - Buffer的容量
direct - buffer的类型. true表示direct buffer, false表示 heap buffer
默认是通过SimpleBufferAllocator类来分配Buffer的。
或者使用下面的方法
// 指定默认的Buffer类型,这里是Heap
IoBuffer.setUseDirectBuffer(false);
// 在Heap上分配一个Buffer
IoBuffer buf = IoBuffer.allocate(1024);
使用第二种方法时别忘了指定默认Buffer类型,否则就是从Heap上分配。
创建自动扩展的Buffer
使用Java的NIO是不能创建一个可以自动扩展的Buffer的,因为NIO的ByteBuffer是固定大小的。对于一个网络应用程序来说如果有能按需扩展的Buffer是非常方便的。为了满足这一点MINA的IoBuffer提供了一个autoExpand属性。它可以自动扩展capacity和limit值。下面来看看如何创建自动扩展Buffer:
IoBuffer buffer = IoBuffer.allocate(8);
buffer.setAutoExpand(true);
buffer.putString("12345678", encoder);
// Add more to this buffer
buffer.put((byte)10);
从内部实现上来说,在上面的例子中当写入的数据量大于8个字节时,IoBuffer会重新分配一个新的ByteBuffer。新的ByteBuffer的容量会翻倍,limit值是最后写入的位置。这里的行为和StringBuffer非常类似。
上面的机制在MINA 3.0中很可能被移除。因为那并不是增加Buffer容量的最佳方式。最好是用ByteBuffer的链表或数组来实现一个InputStream以实现自动容量扩展的功能。
创建了自动缩小的Buffer
有些情况下我们需要把已经分配的字节从Buffer中释放掉,以确保很多的内存空间。IoBuffer提供了autoShrink属性来对应这个需求。如果autoShrink被设置为true,当调用compact方法被调用并且实际使用只有容量的1/4或更小被使用时,IoBuffer会把容量减半。如果想要手动的缩减容量,可以直接调用shrink()方法。
我们看一个例子 :
IoBuffer buffer = IoBuffer.allocate(16);
buffer.setAutoShrink(true);
buffer.put((byte)1);
System.out.println("Initial Buffer capacity = "+buffer.capacity());
buffer.shrink();
System.out.println("Initial Buffer capacity after shrink = "+buffer.capacity());
buffer.capacity(32);
System.out.println("Buffer capacity after incrementing capacity to 32 = "+buffer.capacity());
buffer.shrink();
System.out.println("Buffer capacity after shrink= "+buffer.capacity());
如果初始分配空间是16并且autoShrink属性是true。
我们看到的输出如下:
Initial Buffer capacity = 16
Initial Buffer capacity after shrink = 16
Buffer capacity after incrementing capacity to 32 = 32
Buffer capacity after shrink= 16
让我们来分析一下:
因为我们用16来创建一个Buffer,所以Buffer的初始容量是16。在内部16也是Buffer的最小容量。
这时调用shrink的话容量仍然是16,因为无论怎么缩减容量都不会小于最小容量。
当我们把容量扩展到32时,Buffer的容量变成32。
这时调用shrink,容量缩减为16,从而释放内存空间。
同样,这个机制是默认实现的,你不需要显示的告诉Buffer它可以缩减,
Buffer分配
IoBufferAllocater负责分配和管理Buffer。如果你想要精确的控制Buffer分配策略,就需要实现这个接口。
MINA提供了如下IoBufferAllocater的实现:
SimpleBufferAllocator (默认) - 每次调用allocate都会创建一个新的Buffer
CachedBufferAllocator - 缓存Buffer,使其可以被重复利用。
随着JVM对ByteBuffer的优化,缓存Buffer已经在提升性能方面没什么优势了。
你可以实现IoBufferAllocator接口并且通过setAllocator()来让IoBuffer使用。
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com