ByteBuf 的主要类继承关系
内存分配的角度来分类
1 堆内存字节(HeapByteBuf)缓冲区 :
内存的分配和回收的速度快,可以被JVM自动回收。 缺点是如果进行Socket的I/O读写,需要做一次额外的内存复制,将堆内存的缓冲区复制到Channel中,性能会下降。
2 直接内存(DirectByteBuf)
再堆外进行内存分配,分配和回收的速度慢一些,但是将它写入或者读取将直接在内核内存,减少一次内存复制,读写速度快。
那正是这样,最佳实践是再I/O通信的线程读写缓冲区使用DirectByteBuf ,后端业务消息使用HeapButeBuf,这样组合达到性能最优。
内存回收的角度来分类
基于对象池的ByteBuf和普通的ByteBuf 基于内存池的ByteBuf可以重用ByteBuf 对象,自己维护了一个内存池,可以循环利用ByteBuf对象,提升内存的使用效率,降低由于高负载导致的频繁GC,测试表明使用内存池可以在高负载,大并发的冲击下内存和gc更加平稳。
AbstactByteBuf 源码分析
readBtyes()
writeBytes()
写时扩容原理
采用了先倍增后步进的扩容方式,当内存小的时候,倍增不会造成太大的浪费 因此 到达某个阈值 需要进行步进式的扩容,这个阈值是个经验值,不同的应用场景,值是不同的,netty默认为4MB
重新计算动态扩张后,需要重新创建个新的缓冲区,将原来的缓冲区内容复制到新创建的ByteBuf里面,最后重新设置读写索引和mark标签
操作索引 mark
主要是获取 读写索引 mark 和set 比较简单
重用缓冲区discardReadBytes
主要是 discardReadBytes
1 首先要判断读索引是不是等于零,为零,就没有可重用的。2 如果大于零且读指针不等于写指针,说明已经存在被读取过的可以被遗弃的字节,3 也要调整mark的读写位置。
skipBytes
跳越过不需要读取的字节数。也要去判断要跳跃的字节数是否大于可读取的字节数
AbstractRefenceCountedByteBuf 的源码分析
从类的名字就知道 该类主要是对引用进行计数,类似于JVM内存回收的对象引用计数,用于跟踪对象的分配和销毁,做自动的内存回收
Byte的注意事项
注意ByteBuffer的自动释放 当继承不同的Handler 时 ,有的不会自动释放
不会自动释放的
会自动释放的
在这里被释放掉 调用ReferenceCountUtil.release()
并发操作的问题