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使用。

發佈了15 篇原創文章 · 獲贊 2 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章