内存分配是Netty中最为底层的一部分,主要负责从底层的IO中读取到ByteBuf,然后传递给应用程序,应用程序处理完之后封装为ByteBuf,写回给IO。这块内容相比于Netty的其它模块是非常复杂的。
- 内存类别
- 多线程内存分配竞争
- 不同大小内存如何分配
ByteBuf结构
先了解下ButeBuf结构和常用的API,ByteBuf内部有两个指针,提供了顺序的读写操作,读操作有readerIndex(),写操作有writerIndex()。
如图:
image-20190317084755953-
readerIndex代表从当前指针开始读
-
writerIndex代表从当前位置开始写
-
capacity代表当前ByteBuf的容量
-
0readerIndex之间的数据是无效的,readerIndexwriterIndex之间的数据是可写的,writerIndex~capcity之间的数据是空闲的额,可以写入。当数据不断的增大的时候,会在maxcapacity内对capacity进行扩容
当读取数据直到readerIndex与writerIndex达到同样的值时候,会抛出IndexOutOfBoundsException。
ByteBuf API
主要有以下几类的常用API
- read : 移动读指针
- write: 移动写指针
- set,get: 不会移动指针,在特定的index设置值,或者获取值
- mark,reset: 在读写之前把当时的指针状态保存起来,读写完之后,在调用reset就可以复原原先的操作。这个时候就算进行了读写,也没有改变index。
- readableBytes:this.writerIndex - this.readerIndex ,如上图,(写指针-读指针)之间的数据
- writableBytes:this.capacity - this.writerIndex ,如图,(容量-写指针)之间的数据
- maxWritableBytes:this.maxCapacity - this.writerIndex,(最大容量-写指针)之间的数据
ByteBuf 分类
AbstractByteBuf是ByteBuf的骨架实现,其它的类大都是基于AbstractByteBuf实现。
简单的看两个方法:
public byte readByte() {
// 检查字节是否可读
checkReadableBytes0(1);
int i = readerIndex;
// 读取字节放到子类中实现,不同的子类读取字节的方式不同
byte b = _getByte(i);
// 读指针加1
readerIndex = i + 1;
return b;
}
@Override
public ByteBuf writeByte(int value) {
// 确保是可以进行写的
ensureAccessible();
ensureWritable0(1);
// 写自己放到子类中实现,并且写指针加1
_setByte(writerIndex++, value);
return this;
}
那么分类:
- Pooled与Unpoold:每次是从内存中已经分配好的内存中去取还是重新分配内存。
- Unsafe与非Unsafe:Unsafe可以直接拿到内存地址,也就是是否使用JDK内部的Unsafe对象直接操作操作系统的内存。
- Heap与Direct:Heap直接在堆上分配,参与GC。Direct是在堆外分配,不参与GC。Direct分配的内存需要手动的释放。
最后
关于ByteBuf的简单介绍就到这了。
网友评论