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() 操作。 并且支持池化,减少内存碎片,也支持堆上分配,跟堆外内存两种方式,还有复合模式的支持。