因何而寫
網上關於bytebuffer的文章真的很多,為何在此還要寫一篇呢?主要是基於以下幾點考慮用極易的方式認識一下bytebuffer
bytebuffer之第一眼印象
我們可以把bytebuffer理解成如下幾個成員組成的一個新對象,對,就是一個普通的java對象,像string一樣的java對象。(強調一下,這里只是說這樣理解,實際上有些bytebuffer的實現類並非這樣實現,並且這里只列出掌握bytebuffer所需要的最小知識集合,其它諸如mark等字段本文並不介紹,以免增加初學者的惑度)- byte[] bytes: 用來存儲數據
- int capacity: 用來表示bytes的容量,那么可以想像capacity就等於bytes.size(),此值在初始化bytes后,是不可變的。
- int limit: 用來表示bytes實際裝了多少數據,可以容易想像得到limit <= capacity,此值是可靈活變動的
- int position: 用來表示在哪個位置開始往bytes寫數據或是讀數據,此值是可靈活變動的
bytebuffer之常用操作及各操作對內部變量帶來的變化
創建bytebuffer: ByteBuffer.allocate(6)
寫入一個字節: byteBuffer.put((byte)3)
讀取一個字節: byte bs = byteBuffer.get()
對於剛剛寫好的bytebuffer,我們要讀取它的內容,需要先設置一下position和limit,否則讀的位置就不對
我們看一下,設置position和limit后,bytebuffer的內部變化接下來,我們就可以讀取剛才寫入的數據了byteBuffer.position(0); //設置position到0位置,這樣讀數據時就從這個位置開始讀 byteBuffer.limit(1); //設置limit為1,表示當前bytebuffer的有效數據長度是1
byte bs = byteBuffer.get();
bytebuffer之使用心得
這里說的是作者本人使用bytebuffer的一些心得,這些與其說是心得,不如說是實踐+測試得來的一些經驗,所以並不保證就是權威的,歡迎有更深研究的朋友來合理討論,如果有不同意見,可以以更好的論據來說服對方。HeapByteBuffer.get(byte[], int, int)效率不如 System.arraycopy()
前者實現的原理是用for循環來做的,后者是內存復制,t-io一般是用后者來做bytebuffer的組合,譬如SendRunnable.java的下面這段代碼
注意:如果DirectBuffer並不能用System.arraycopy來代替get(byte[], int, int),因為這貨的內部實現不是byte[]的ByteBuffer allByteBuffer = ByteBuffer.allocate(allBytebufferCapacity); byte[] dest = allByteBuffer.array(); for (ByteBuffer byteBuffer : byteBuffers) { if (byteBuffer != null) { int length = byteBuffer.limit(); int position = allByteBuffer.position(); System.arraycopy(byteBuffer.array(), 0, dest, position, length); allByteBuffer.position(position + length); } }
jdk自帶的bytebuffer已經足夠好用
有一些nio/aio框架喜歡自己弄一套bytebuffer來,既增加了作者自己的工作量,又增加了用戶的學習成本,但我們要知道一點,nio/aio在發送數據時,最終的參數是jdk的bytebuffer,我們真的有必要再作一次轉換和計算嗎?盡管某些中間過程是“零拷貝”(這個“零拷貝”也是有額外的計算成本的)的,但是jdk版bytebuffer的誕生到發送完畢,這整個過程經歷了哪些操作呢?真的是如某書某博客上所說的“零拷貝”嗎?更不應該把某些對象池的做法也牽強附會到“零拷貝”的概念中來----對象池屬對象重復利用范疇,既然是重復利用自然便已經默認有零拷貝的屬性了,但是對象池本身的維護也是需要消耗資源的,所以並不是所有場景說用了對象池,性能就提升了,有時候用不好反而增加負擔,所以萬事要以測試數據為准,不應盲目人雲亦雲!
最后附上bytebuffer的示例程序
這里附上bytebuffer的示例程序,用戶可以自己debug觀察觀察,增加bytebuffer的相關概念,以便更靈活的運用bytebufferimport java.nio.ByteBuffer; /** * @author tanyaowu * 2017年5月1日 上午9:00:50 */ public class Ts { /** * * @author: tanyaowu */ public Ts() { } /** * @param args * @author: tanyaowu */ public static void main(String[] args) { ByteBuffer byteBuffer = ByteBuffer.allocate(6); byteBuffer.put((byte)3); byteBuffer.position(0); //設置position到0位置,這樣讀數據時就從這個位置開始讀 byteBuffer.limit(1); //設置limit為1,表示當前bytebuffer的有效數據長度是1 byte bs = byteBuffer.get(); System.out.println(byteBuffer); } }