前言
netty学习系列笔记总结,bytebuf总结,错误之处欢迎指正, 共同学习
ByteBuf介绍
内存分配负责把数据从底层 IO 读到 ByteBuf 传递应用程序,应用程序处理完之后再把数据封装成 ByteBuf 写回到 IO,ByteBuf 是直接与底层 IO 打交道的抽象
Demo
1 | public class Scratch { |
ByteBuf结构以及重要api
ByteBuf结构
1 | +-------------------+------------------+------------------+ |
read,write,set方法
read 方法读数据在当前 readerIndex 指针开始往后读, readByte()/readShort()/readInt()/readLong() 把 readerIndex 指针往前移一格,读 readerIndex 指针后面 1/2/4/8 个字节数据,write 方法把数据写到 ByteBuf, read/write 方法 readerIndex/writerIndex 指针往后移动,set 方法在当前指针设置成指定值,不会移动指针
mark,reset方法
mark 方法标记当前 readerIndex/writerIndex 指针,reset 方法还原之前读/写数据 readerIndex/writerIndex 指针,不会改变 readerIndex/writerIndex 指针。确保指针读/写完数据能够保持原样
1 | public int readableBytes() { |
ByteBuf分类
AbstractByteBuf 抽象实现 ByteBuf。保存和标记读写指针,记录 ByteBuf 最多分配容量及抽象方法子类实现
1 | 1.Pooled 和 Unpooled |
ByteBufAllocator分析
ByteBuf 通过 ByteBufAllocator 内存分配管理器分配内存,内存分配管理器最顶层抽象负责分配所有类型的内存
1 | 1.ByteBufAllocator功能 |
UnPooledByteBufAllocator分析
1 | 1.heap内存的分配 |
PooledByteBufAllocator概述
1 | 1.拿到线程局部缓存PoolThreadCache->threadCache.get() |
directArena分配direct内存的流程
1 | 1.从对象池里面拿到PooledByteBuf进行复用 |
内存规格的介绍
1 | 0 <-tiny->512B<-small->8K<-normal->16M<-huge-> |
缓存数据结构
1 | --------------------------MemoryRegionCache---------------------------- |
命中缓存的分配流程
1 | 申请内存调用 normalizeCapacity() 方法 reqCapacity 大于Tiny找2的幂次方数值确保数值大于等于reqCapacity,Tiny内存规格以16的倍数自增分段规格化,目的是为了缓存分配后续 release 放到缓存里面而不需要释放,调用cache 的 allocateTiny()/allocateSmall()/allocateNormal()方法分配缓存 |
arena、chunk、page、subpage概念
1 | PoolThreadCache |
page 级别内存分配
1 | 1.尝试在现有的chunk上分配 |
subpage 级别的内存分配
1 | 调用tinyIdx()方法计算normCapacity>>4获取tinySubpagePools的索引tableIdx,根据tableIdx获取tinySubpagePools下标位置的PoolSubpage头节点head,默认情况头节点head无任何内存信息指向它自己表示当前头节点head为空,头节点head的后置节点next非头节点head本身调用initBufWithSubpage()方法初始化PooledByteBuf,反之调用allocateNormal()方法进行subpage级别的内存分配 |
ByteBuf的回收
调用ByteBuf的release()方法使用AbstractReferenceCountedByteBuf的release0()方法判断引用数量是否等于decrement相等调用deallocate()方法设置handle为-1表示不指向任何一块内存以及memory设置为空
1 | 1.连续的内存区段加到缓存 |
总结
1 | 1.ByteBuf的api和分类 |