Apache Mina 文档翻译 - 第八章 - IoBuffer

第八章 - 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使用。

猜你喜欢

转载自zjumty.iteye.com/blog/1880940
今日推荐