Netty中的PooledByteBuf池化原理剖析

PooledByteBuf

PooledByteBuf是池化的ByteBuf,提高了内存分配与释放的速度,它本身是一个抽象泛型类,
有三个子类:PooledDirectByteBuf、PooledHeapByteBuf、PooledUnsafeDirectByteBuf.

Jemalloc算法

Netty的PooledByteBuf采用与jemalloc一致的内存分配算法。基本思路可用这样的情景类比,想象一下电商的配送流程。当顾客采购小件商品(比如书籍)时,直接从同城仓库送出;当顾客采购大件商品(比如电视)时,从区域仓库送出;当顾客采购超大件商品(比如汽车)时,则从全国仓库送出。Netty的分配算法与此相似。Netty中,Tiny和Small类型的请求都首先从同城仓库(ThreadCache-tcache)送出;如果同城仓库没有,则会从区域。仓库(PoolArena)送出,Normal类型的请求则从区域仓库(PoolArena)送出,Huge类型的请求则从全国仓库(系统内存)送出。
Netty中规定:

  • 1.内存分配的最小单位为16B
  • 2.小于512B的请求为Tiny,512B<x<8KB(PageSize)的请求为Small,8KB<=X<=16MB(ChunkSize)的请求为Normal,大于16MB(ChunkSize)的请求为Huge
  • 3.Tiny、Small、Normal、Huge中还有细层级,小于Tiny的请求以16B为起点每次增加16B作为一个层级,也就是
    Tiny中还有16B、32B、48B、…480B、496B的层级
    其他类型的则是翻倍:
    Small中还有512B、1KB、2KB、4KB的层级
    Normal中还有8KB、16KB、32KB…8MB、16MB的层级
    Huge中还有32MB、64MB…的层级
  • 4.不管请求的大小,都会将向上规范化,比如:请求分配511B、512B、513B,将依次规范化为512B、512B、1KB
    为了提高内存分配效率并减少内部碎片,jemalloc算法将Arena切分为小块Chunk,根据每块的内存使用率又将小块组合为以下集中状态QINIT,Q0,Q25,Q50,Q75,Q100。Chunk块可以在这几种状态间随着内存使用率的变化进行转移,内存使用率和状态转移如图所示。
    在这里插入图片描述
    其中横轴表示内存使用率(百分比),纵轴表示状态,可以看到:
    QINIT的内存使用率为[0,25),Q0为(0,50),Q100为[100,100]等等。
    Chunk的初始状态为QINIT,当使用率达到25时转移到Q0状态,再次达到50时转移到Q25,依次类推直到Q100;当内存释放时又从Q100转移到Q75,直到Q0状态且内存使用率为0时,该Chunk从Arena中删除。像qinit、q000、q075因为本身要维护很多Chunk块,所以内部是以链表的形式来组织Chunk块,同时qinit、q000、q075本身又组织为一个近似的双向链表,如图所示。
    在这里插入图片描述
    虽然已将Arena切分成小块的Chunk,但实际上Chunk是相当大的内存块,在Netty中默认使用16MB。为了进一步提高内存利用率,并减少内部碎片,需要继续将Chunk切分为小的快Page.一个典型的切换将Chunk切分为2048块,可知Page的大小为:16MB/2048=8KB.一个好的内存分配算法,应使得已分配内存块尽可能保持连续,这将大大减少内部碎片,由此jemalloc使用伙伴分配算法尽可能提高连续性。伙伴分配算法的基本思想是:
    我们知道一个Chunk切分为2048块Page,将这些Page作为叶子节点,然后组织起一个满二叉树,然后按层分配满足要求的内存块。以待分配序列8KB、16KB、8KB为例分析分配过程(每个Page大小8KB):
  • 8KB–需要一个Page,第11层满足要求,故分配2048节点即Page0
  • 16KB-需要两个Page,故需要在第10层进行分配,而1024节点的子节点2048已分配,从左到右找到满足要求的1025节点,故分配节点1025即Page2和Page3
  • 8KB–需要一个Page,第11层满足要求,2048已分配,从左到右找到2049节点即Page1进行分配。分配结束后,已分配连续的Page0-Page3,这样的连续内存块,大大减少内部碎片并提高内存使用率,为了实现伙伴算法,Netty中使用了memoryMap和depthMap来表示两棵二叉树,其中MemoryMap存放分配信息,depthMap存放节点的高度信息

在这里插入图片描述

我们在前面说过,一个page是8KB,但是Netty又支持Tiny、Small这种小于8KB,最小可达16B的内存分配请求,每次都分配一个page,很浪费。为了进一步切分Page成更小的SubPage,SubPage是jemalloc中内存分配的最小单位,不能再进行切分.SubPage切分的单位并不固定,以第一次请求分配的大小为单位(最小切分单位为16B).比如,第一次请求分配32B,则Page按照32B均等切分为256块;第一次请求请求16B,则Page按照16B均等切分512块。为了便于内存分配和管理,根据SubPage的切分单位进行分组,对每个组而言,Arena会以双向链表的形式进行管理。那么根据切分的单位的大小和Page的大小,SubPage分为两类:tinySubPagePools和smallSubPagePools,tinySubPage中的subPage的大小,从16字节到496个字节,共有32个元素,smallSubPagePools则有512字节、1024、2048、4096共4个元素。如图所示。

在Arena数量上,为了减少各个线程进行内存分配时竞争,Netty中会有多个Arena,默认的数量与处理器的个数有关,线程首次分配内存时,首先会为其分配一个固定的Arena
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
左图表示每个节点的编号,注意从1开始,省略0是因为这样更容易计算父子关系:子节点加倍,父节点减半,比如512的子节点为1024=512 *2.右图表示每个节点的深度,注意从0开始。在代表二叉树的数组中,左图中节点上的数字作为数组索引即id,右图节点上的数字作为值。初始
状态时,memoryMap和depthMap相等,可知一个id为512节点的初始值为9,memoryMap[512]=depthMap[512]=9,depthMap的值初始化后不再改变,memoryMap的值随着节点分配而改变,当一个节点被分配以后,
该节点的值设置为12(最大高度+1)表示不可用,并且会更新祖先节点的值。
在这里插入图片描述
分配过程如下:
4号节点被完全分配,将高度值设置为12表示不可用。
4号节点的父亲节点即2号节点,将高度值更新为两个子节点的较小值;其他祖先节点亦然,直到高度值更新到根节点,可推知,memoryMap数组的值有如下三种情况:

  • memoryMap[id]=depthMap[id] – 该节点没有被分配
  • memoryMap[id] > depthMap[id] – 至少有一个子节点被分配,不能再分配该高度满足的内存,但可以根据实际分配较小一些的内存,比如,上图中分配了4号子节点的2号节点,值从1更新为2,表示该节点不能再分配8MB的只能最大分配4MB内存,因为分配了4号节点后只剩下5号节点可用。
  • memoryMap[id] = 最大高度 +1 (本例中12) – 该节点及其子节点已被完全分配,没有剩余空间。

PoolThreadCache.

同时在Netty中为了提升性能,并不会一开始就从PoolArena中分配,因为Arena为几个线程共享,而是先从每个线程自己的PoolThreadCache中去获取。当然开始的是偶,这些Cache里面都是没有值的,要先从PoolArena中获取,当释放Buf的时候,才会把之前分配的内存大小放到该cache里面,当下次申请内存的时候,就会先从PoolThreadCache中找。
PoolThreadCache中则维护了6个这样的线程缓存区域,3个堆内存相关,3个直接内存相关,分别对应着三种
分配内存的大小small类型的数组的大小为4,而tiny、normal数组的大小分别为32、3,smallSubPageHeapCache的数组长度为4,依次缓存[512K,1024K,2048K,4096K]大小的缓存,每个元素对应的缓存
queue中的元素个数不能超过256个,而tinySubPageHeapCaches数组缓存的是[16B,32B,…,496B]大小的内存块,每个元素,对应的缓存queue中元素个数不能超过512个,normalHeapCaches数组结构相同,但是只缓存[8K,16K,32K]大小的内存块,每个元素对应的缓存queue中元素个数不超过64个。每一个MemoryRegionCache中又包含一个队列。队列中的每个元素类型为Entry,Entry中又包含了一个PoolChunk,以方便对内存的管理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/400563.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java在当前项目创建文件

public static void main(String[] arge) throws IOException {File file new File("dade02\\dade");//不存在创建if(!file.exists()){file.mkdirs();}File file1 new File("dade02\\dade\\daade.txt");file1.createNewFile();}或者 public static void …

Rust ?运算符 Rust读写txt文件

一、Rust &#xff1f;运算符 &#xff1f;运算符&#xff1a;传播错误的一种快捷方式。 如果Result是Ok&#xff1a;Ok中的值就是表达式的结果&#xff0c;然后继续执行程序。 如果Result是Err&#xff1a;Err就是整个函数的返回值&#xff0c;就像使用了return &#xff…

租用海外服务器,自己部署ChatGPT-Next-Web,实现ChatGPT聊天自由,还可以分享给朋友用

前言 如果有好几个人需要使用ChatGPT&#xff0c;又没有魔法上网环境&#xff0c;最好就是自己搭建一个海外的服务器环境&#xff0c;然后很多人就可以同时直接用了。 大概是情况是要花80元租一个一年的海外服务器&#xff0c;花15元租一个一年的域名&#xff0c;然后openai 的…

搜索专项---DFS之连通性模型

文章目录 迷宫红与黑 一、迷宫OJ链接 本题思路:DFS直接搜即可。 #include <iostream> #include <cstring> #include <algorithm>constexpr int N110;int n; char g[N][N]; bool st[N][N]; int x1, y1, x2, y2;int dx[4] {-1, 0, 1, 0}, dy[4] {0, 1, 0, …

多线程完成文件拷贝:2024/2/21

作业1&#xff1a;使用多线程完成两个文件的拷贝 要求&#xff1a;第一个线程拷贝前一半&#xff0c;第二个线程拷贝后一半&#xff0c;主线程回收两个线程的资源 代码&#xff1a; #include <myhead.h>//定义结构体 typedef struct Info {char *src;char *dest;int s…

springboot访问webapp下的jsp页面

一&#xff0c;项目结构。 这是我的项目结构&#xff0c;jsp页面放在WEB-INF下的page目录下面。 二&#xff0c;file--->Project Structure,确保这两个地方都是正确的&#xff0c;确保Source Roots下面有webapp这个目录&#xff08;正常来说&#xff0c;应该本来就有&#…

c语言经典测试题1

1.题1 int x5,y7; void swap() { int z; zx; xy; yz; } int main() { int x3,y8; swap(); printf("%d,%d\n"&#xff0c;x, y); return 0; } A: 5,7 B: 7,5 C: 3,8 D: 8,3 大家思考一下选哪一个呢&#xff1f; 我们来分析一下&#xff1a;上述代码中我们创建了4…

【JavaWeb】网上蛋糕商城-项目搭建

学习目标 了解网上蛋糕商城的项目需求 了解网上蛋糕商城的功能结构 熟悉E-R图和数据表的设计 熟悉项目环境的搭建 通过前面章节的学习&#xff0c;相信读者应该已经掌握了Web开发的基础知识&#xff0c;学习这些基础知识就是为开发Web网站奠定基础。如今&#xff0c;电子商…

golang JSON数据格式 XML数据格式 Gob(这玩意真的有人用吗?)

接着摸鱼&#xff0c;摸鱼一时爽&#xff0c;一直摸鱼一直爽&#xff0c;接着搞golang 不是所有的数据都可以编码为 JSON 类型&#xff0c;只有验证通过的数据结构才能被编码&#xff1a; JSON 对象只支持字符串类型的 key&#xff1b;要编码一个 Go map 类型&#xff0c;map 必…

stm32——hal库学习笔记(DAC)

这里写目录标题 一、DAC简介&#xff08;了解&#xff09;1.1&#xff0c;什么是DAC&#xff1f;1.2&#xff0c;DAC的特性参数1.3&#xff0c;STM32各系列DAC的主要特性 二、DAC工作原理&#xff08;掌握&#xff09;2.1&#xff0c;DAC框图简介&#xff08;F1&#xff09;2.2…

Hive JDBC

Hive远程模式搭建好之后&#xff0c;可以使用Beeline客户端或JDBC远程访问Hive了 启动HiveServer2服务 $ hive --service hiveserver2 & 新建Java Maven项目&#xff0c;在pom.xml中添加以下依赖 <dependencies><dependency><groupId>jdk.tools</g…

曝光一下不发年终奖的企业

原文连接&#xff1a; 曝光一下不发年终奖的企业 今日热帖&#xff0c;看到网上发布的一篇帖子&#xff1a;请曝光一下不发年终奖的企业&#xff01; 结果留言上百条&#xff0c;除了私企&#xff0c;还有很多国企&#xff0c;银行等。而且还有一些我们认为应该很赚钱的企业&a…

opencv图像放缩与插值-resize函数

在OpenCV中&#xff0c;resize函数用于对图像进行尺寸调整&#xff08;放大或缩小&#xff09;&#xff0c;这个过程中通常需要用到插值方法来计算新尺寸下图像像素的值。插值方法对于放缩的质量有着直接影响。 void resize(InputArray src, OutputArray dst, Size dsize, dou…

Linux 性能分析工具汇总

Linux 性能分析工具汇总 出于对Linux操作系统的兴趣&#xff0c;以及对底层知识的强烈欲望&#xff0c;因此整理了这篇文章。本文也可以作为检验基础知识的指标&#xff0c;另外文章涵盖了一个系统的方方面面。如果没有完善的计算机系统知识&#xff0c;网络知识和操作系统知识…

k-邻近算法(kNN)

目录 k-近邻算法概述 k-近邻算法的一般流程 kNN算法伪代码 k-近邻算法概述 优点&#xff1a;精度高、对异常值不敏感、无数据输入假定 缺点&#xff1a;计算复杂度高、空间复杂度高 适用数据范围&#xff1a;数值型和标称型 k-近邻算法的一般流程 &#xff08;1&#x…

2024年最新1000个Java毕业设计选题参考

文章目录 2024年最新Java毕业设计选题参考一、Java毕业设计选题参考二、javaweb毕业设计选题三、springboot/ssm毕业设计选题参考 源码获取&#xff1a; 博主介绍&#xff1a;✌全网粉丝7W,CSDN博客专家、Java大数据领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/In…

强化学习(SAC)

SAC—— soft actor-critic SAC算法是一种现代的深度强化学习算法&#xff0c;它结合了基于策略的和基于价值的方法。SAC的核心思想是最大化期望回报的同时保持策略的随机性&#xff0c;这有助于提高探索环境的效率&#xff0c;并且通常可以赵高更好的策略。 发展史&#xff…

C++从入门到精通 第十四章(STL容器)【上】

写在前面&#xff1a; 本系列专栏主要介绍C的相关知识&#xff0c;思路以下面的参考链接教程为主&#xff0c;大部分笔记也出自该教程&#xff0c;笔者的原创部分主要在示例代码的注释部分。除了参考下面的链接教程以外&#xff0c;笔者还参考了其它的一些C教材&#xff08;比…

接口自动化测试利器,使用Rest Assured进行REST API测试

我们在做接口测试时&#xff0c;一般在代码中会使用HttpClient&#xff0c;但是HttpClient相对来讲还是比较麻烦的&#xff0c;代码量也相对较多&#xff0c;对于新手而言上手会比较难一点&#xff0c;今天我们来看下另一个接口测试工具包REST Assured REST Assured是一个流行…

Qt 基础之进度条 - QProgressDialog和QProgressBar

Qt 基础之进度条 - QProgressDialog和QProgressBar 引言一、QProgressDialog例程1.1 效果展示1.2 源码 二、QProgressBar例程2.1 效果展示2.2 源码 三、QProgressBar进阶 引言 进度条的作用是用于显示任务或操作的进度&#xff0c;以便用户了解当前任务的完成情况。它可以提供…