Java 中基本類型所佔的字節數
byte 1字節
short 2字節
int 4字節
long 8字節
char 2字節 可以存儲一個漢字
float 4字節
double 8字節
getXXX setXXX不改變指針的操作
public class ByteBufTest002 {
public static void main(String[] args) {
ByteBuf byteBuf = Unpooled.copiedBuffer("ABCDEFH", CharsetUtil.UTF_8);
System.out.println(byteBuf.writerIndex());
for (int i = 0; i < byteBuf.writerIndex() ; i++){
byte b = byteBuf.getByte(i);
System.out.println((char)b + "---------" + byteBuf.readerIndex());
}
System.out.println();
for (int i = 0 ; i < byteBuf.writerIndex(); i++){
byteBuf.setByte(1,'l');
System.out.println(byteBuf.writerIndex());
}
}
}
執行結果
7
A---------0
B---------0
C---------0
D---------0
E---------0
F---------0
H---------0
7
7
7
7
7
7
7
結論:
get跟set開頭的方法不會改變readerIndex 跟 writerIndex
Buffer中的指針變量跟區域
discardable 被讀過的廢棄掉的
* <pre>
* +-------------------+------------------+------------------+
* | discardable bytes | readable bytes | writable bytes |
* | | (CONTENT) | |
* +-------------------+------------------+------------------+
* | | | |
* 0 <= readerIndex <= writerIndex <= capacity
* </pre>
可讀字節
public class ByteBufTest003 {
public static void main(String[] args) {
ByteBuf byteBuf = Unpooled.copiedBuffer("ABCDEFH", CharsetUtil.UTF_8);
//可讀的字節
while (byteBuf.isReadable()){
System.out.println((char) byteBuf.readByte() + " ====== " +byteBuf.readerIndex());
}
//已經讀完了再讀就會發生異常
byteBuf.readByte();
}
}
執行結果
A ====== 1
B ====== 2
C ====== 3
D ====== 4
E ====== 5
F ====== 6
H ====== 7
Exception in thread "main" java.lang.IndexOutOfBoundsException: readerIndex(7) + length(1) exceeds writerIndex(7): UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 7, widx: 7, cap: 21)
at io.netty.buffer.AbstractByteBuf.checkReadableBytes0(AbstractByteBuf.java:1495)
at io.netty.buffer.AbstractByteBuf.readByte(AbstractByteBuf.java:745)
at com.clown.netty.bytebuftest.ByteBufTest003.main(ByteBufTest003.java:16)
總結 wirteXXX,readXXX 會改變readerIndex 跟 writerIndex。
可寫字節
/**
* 可寫字節
*/
public class ByteBufTest004 {
public static void main(String[] args) {
ByteBuf byteBuf = Unpooled.copiedBuffer("ABCDEFH", CharsetUtil.UTF_8);
SecureRandom random = new SecureRandom();
System.out.println("capacity is" + byteBuf.capacity());
while (byteBuf.writableBytes() > 0 ){
byteBuf.writeByte(random.nextInt());
System.out.println(byteBuf.writerIndex());
}
}
}
ByteBufAllocator
- 獲得ByteBufAllocator
//通過ChannelHandlerContext
ByteBufAllocator allocator = channelHandlerContext.alloc();
ByteBuf buffer = allocator.buffer(16, 32);
//通過Channel
ByteBufAllocator allocator1 = channelHandlerContext.channel().alloc();
ByteBuf byteBuf2 = allocator1.buffer(32);
//創建DirectByteBuf
ByteBuf directByteBuf = allocator1.directBuffer(16);
Netty提供了兩種ByteBufAllocator的實現:PooledByteBufAllocator和Unpooled-ByteBufAllocator。前者池化了ByteBuf的實例以提高性能並最大限度地減少內存碎片。
此實現使用了一種稱爲jemalloc的已被大量現代操作系統所採用的高效方法來分配內存,後面是每次都創建一個新的。
雖然Netty默認使用了PooledByteBufAllocator,但這可以很容易地通過Channel-ConfigAPI或者在引導你的應用程序時指定一個不同的分配器來更改。
UnpooledBuffer
名稱 | 描述 |
---|---|
buffer(), buffer(int capacity), buffer(int capacity,int maxCapacity) |
返回一個未池化得基於堆存儲得ByteBuf |
directBuffer() directBuffer(int initialCapacity) directBuffer(int initialCapacity, int maxCapacity) |
返回一個未被池化的ByteBuf |
wrappedBuffer() | 返回一個包裝了給定數據的ByteBuf |
copiedBuffer() | 返回一個複製了給定數據的ByteBuf |
clear() 方法 readerIndex 跟writeIndex 都等於 0
* <pre>
* BEFORE clear()
*
* +-------------------+------------------+------------------+
* | discardable bytes | readable bytes | writable bytes |
* +-------------------+------------------+------------------+
* | | | |
* 0 <= readerIndex <= writerIndex <= capacity
*
*
* AFTER clear()
*
* +---------------------------------------------------------+
* | writable bytes (got more space) |
* +---------------------------------------------------------+
* | |
* 0 = readerIndex = writerIndex <= capacity
* </pre>
discardReadBytes()方法對讀寫索引的影響
* <pre>
* BEFORE discardReadBytes()
*
* +-------------------+------------------+------------------+
* | discardable bytes | readable bytes | writable bytes |
* +-------------------+------------------+------------------+
* | | | |
* 0 <= readerIndex <= writerIndex <= capacity
*
*
* AFTER discardReadBytes()
*
* +------------------+--------------------------------------+
* | readable bytes | writable bytes (got more space) |
* +------------------+--------------------------------------+
* | | |
* readerIndex (0) <= writerIndex (decreased) <= capacity
* </pre>
clear() 方法比較的輕量級將兩個指針都指到了零位置上。雖然discardReadBytes 也可以提供新的內存空間來往ByteBuf 來寫數據,但是它會涉及到數據的複製。所以建議使用clear 方法。
ByteBuf 通過兩個指針變量來維護底層讀寫。避免了NIO ByteBuffer的flip() 操作。 並且支持池化,減少內存碎片,也支持堆上分配,跟堆外內存兩種方式,還有複合模式的支持。