Netty分布式ByteBuf怎么使用命中缓存分配


今天小编给大家分享一下Netty分布式ByteBuf怎么使用命中缓存分配的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。回顾上一小节的内容, 我们讲到PoolThreadCache中维护了三个缓存数组(实际上是六个, 这里仅仅以Direct为例, heap类型的逻辑是一样的): tinySubPageDirectCaches, smallSubPageDirectCaches, 和normalDirectCaches分别代表tiny类型, small类型和normal类型的缓存数组这三个数组保存在PoolThreadCache的成员变量中:其中是在构造方法中进行了初始化:这里上面的小节已经分析过, 这里创建了一个缓存数组, 这个缓存数组的长度,也就是numCaches, 在不同的类型, 这个长度不一样, tiny类型长度是32, small类型长度为4, normal类型长度为3我们知道, 缓存数组中每个节点代表一个缓存对象, 里面维护了一个队列, 队列大小由PooledByteBufAllocator类中的tinyCacheSize, smallCacheSize, normalCacheSize属性决定的, 这里之前小节已经剖析过其中每个缓存对象, 队列中缓存的ByteBuf大小是固定的, netty将每种缓冲区类型分成了不同长度规格, 而每个缓存中的队列缓存的免费云主机域名ByteBuf的长度, 都是同一个规格的长度, 而缓冲区数组的长度, 就是规格的数量比如, 在tiny类型中, netty将其长度分成32个规格, 每个规格都是16的整数倍, 也就是包含0B, 16B, 32B, 48B, 64B, 80B, 96B……496B总共32种规格, 而在其缓存数组tinySubPageDirectCaches中, 这每一种规格代表数组中的一个缓存对象缓存的ByteBuf的大小, 我们以tinySubPageDirectCaches[1]为例(这里下标选择1是因为下标为0代表的规格是0B, 其实就代表一个空的缓存, 这里不进行举例), 在tinySubPageDirectCaches[1]的缓存对象中所缓存的ByteBuf的缓冲区长度是16B, 在tinySubPageDirectCaches[2]中缓存的ByteBuf长度都为32B, 以此类推, tinySubPageDirectCaches[31]中缓存的ByteBuf长度为496B有关类型规则的分配如下:tiny:总共32个规格, 均是16的整数倍, 0B, 16B, 32B, 48B, 64B, 80B, 96B……496Bsmall:4种规格, 512b, 1k, 2k, 4knomal:3种规格, 8k, 16k, 32k这样, PoolThreadCache中缓存数组的数据结构为大概了解缓存数组的数据结构, 我们再继续剖析在缓冲中分配内存的逻辑首先通过normalizeCapacity方法进行内存规格化if(!isTiny(reqCapacity))代表如果大于tiny类型的大小, 也就是512, 则会找一个2的幂次方的数值, 确保这个数值大于等于reqCapacity如果是tiny, 则继续往下if((reqCapacity & 15) == 0)这里判断如果是16的倍数, 则直接返回如果不是16的倍数, 则返回(reqCapacity & ~15) + 16, 也就是变成最小大于当前值的16的倍数值从上面规格化逻辑看出, 这里将缓存大小规格化成固定大小, 确保每个缓存对象缓存的ByteBuf容量统一if(isTinyOrSmall(normCapacity))这里是根据规格化后的大小判断是否tiny或者small类型, 我们跟到方法中:这里是判断如果normCapacity小于一个page的大小, 也就是8k代表其实tiny或者small继续看allocate方法:如果当前大小是tiny或者small, 则isTiny(normCapacity)判断是否是tiny类型, 跟进去:这里是判断如果小于512, 则认为是tiny再继续看allocate方法:如果是tiny, 则通过cache.allocateTiny(this, buf, reqCapacity, normCapacity)在缓存上进行分配我们就以tiny类型为例, 分析在缓存上分配ByteBuf的流程我们跟进去, 进入到了PoolThreadCache的allocateTiny方法中:这里有个方法cacheForTiny(area, normCapacity), 这个方法的作用是根据normCapacity找到tiny类型缓存数组中的一个缓存对象我们跟进cacheForTiny:PoolArena.tinyIdx(normCapacity)是找到tiny类型缓存数组的下标继续跟tinyIdx:这里直接将normCapacity除以16, 通过前面的内容我们知道, tiny类型缓存数组中每个元素规格化的数据都是16的倍数, 所以通过这种方式可以找到其下标, 参考图5-2, 如果是16B会拿到下标为1的元素, 如果是32B则会拿到下标为2的元素if(area.isDirect())这里判断是否是分配堆外内存, 因为我们是按照堆外内存进行举例, 所以这里为true再继续跟到cache(tinySubPageDirectCaches, idx)方法中:这里我们看到直接通过下标的方式拿到了缓存数组中的对象回到PoolThreadCache的allocateTiny方法中:拿到了缓存对象之后, 我们跟到allocate(cacheForTiny(area, normCapacity), buf, reqCapacity)方法中:这里通过cache.allocate(buf, reqCapacity)进行继续进行分配再继续往里跟, 跟到内部类MemoryRegionCache的allocate(PooledByteBuf buf, int reqCapacity)方法中:这里首先通过queue.poll()这种方式弹出一个entry, 我们之前的小节分析过, MemoryRegionCache维护着一个队列, 而队列中的每一个值是一个entry这里重点关注chunk和handle的这两个属性, chunk代表一块连续的内存, 我们之前简单介绍过, netty是通过chunk为单位进行内存分配的, 我们之后会对chunk进行剖析handle相当于一个指针, 可以唯一定位到chunk里面的一块连续的内存, 之后也会详细分析这样, 通过chunk和handle就可以定位ByteBuf中指定一块连续内存, 有关ByteBuf相关的读写, 都会在这块内存中进行我们回到MemoryRegionCache的allocate(PooledByteBuf buf, int reqCapacity)方法:弹出entry之后, 通过initBuf(entry.chunk, entry.handle, buf, reqCapacity)这种方式给ByteBuf初始化, 这里参数传入我们刚才分析过的当前Entry的chunk和hanle因为我们分析的tiny类型的缓存对象是SubPageMemoryRegionCache类型,所以我们继续跟到SubPageMemoryRegionCache类的initBuf(entry.chunk, entry.handle, buf, reqCapacity)方法中:这里的chunk调用了initBufWithSubpage(buf, handle, reqCapacity)方法, 其实就是PoolChunk类中的方法我们继续跟initBufWithSubpage:这里有关bitmapIdx(handle)相关的逻辑, 会在后续的章节进行剖析, 这里继续往里跟:这里我们先关注init方法, 因为我们是以PooledUnsafeDirectByteBuf为例, 所以这里走的是PooledUnsafeDirectByteBuf的init方法首先调用了父类的init方法, 再跟进去:这里将PooledUnsafeDirectByteBuf的各个属性进行了初始化this.chunk = chunk这里初始化了chunk, 代表当前的ByteBuf是在哪一块内存中分配的this.handle = handle这里初始化了handle, 代表当前的ByteBuf是这块内存的哪个连续内存有关offset和length, 我们会在之后的小节进行分析, 在这里我们只需要知道, 通过缓存分配ByteBuf, 我们只需要通过一个chunk和handle, 就可以确定一块内存以上就是通过缓存分配ByteBuf对象的过程我们回到MemoryRegionCache的allocate(PooledByteBuf buf, int reqCapacity)方法:分析完了initBuf方法, 再继续往下看entry.recycle()这步是将entry对象进行回收, 因为entry对象弹出之后没有再被引用, 可能gc会将entry对象回收, netty为了将对象进行循环利用, 就将其放在对象回收站进行回收我们跟进recycle方法chunk = null和handle = -1表示当前Entry不指向任何一块内存recyclerHandle.recycle(this)将当前entry回收, 有关对象回收站, 我们会在后面的章节详细剖析以上就是“Netty分布式ByteBuf怎么使用命中缓存分配”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注百云主机行业资讯频道。

相关推荐: ChatGPT跨越认知边界实例分析

这篇文章主要讲解了“ChatGPT跨越认知边界实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“ChatGPT跨越认知边界实例分析”吧!我的有的朋友跟我说,用ChatGPT编程需要你至少要跟他对等水平,因为…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 07/24 11:33
下一篇 07/24 11:47

相关推荐