Netty源码分析第5章(ByteBuf)----第5节: directArena分配缓冲区概述
Netty源码分析第五章: ByteBuf
第五节: directArena分配缓冲区概述
上一小节简单分析了PooledByteBufAllocator中, 线程局部缓存和arean的相关逻辑, 这一小节简单分析下directArena分配缓冲区的相关过程
回到newDirectBuffer中:
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {PoolThreadCache cache = threadCache.get();PoolArena<ByteBuffer> directArena = cache.directArena;ByteBuf buf;if (directArena != null) { buf = directArena.allocate(cache, initialCapacity, maxCapacity);} else {if (PlatformDependent.hasUnsafe()) {buf = UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);} else {buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);}}return toLeakAwareBuffer(buf); }
获取了directArena对象之后, 通过allocate方法分配一个ByteBuf, 这里allocate方法是PoolArena类中的方法
跟到allocate方法中:
PooledByteBuf<T> allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) { PooledByteBuf<T> buf = newByteBuf(maxCapacity); allocate(cache, buf, reqCapacity);return buf; }
首先通过newByteBuf获得一个ByteBuf对象
再通过allocate方法进行分配, 这里要注意, 这里进行分配的时候是线程私有的directArena进行分配
我们跟到newByteBuf方法中
因为是directArena调用的newByteBuf, 所以这里会进入DirectArena类的newByteBuf中:
protected PooledByteBuf<ByteBuffer> newByteBuf(int maxCapacity) { if (HAS_UNSAFE) { return PooledUnsafeDirectByteBuf.newInstance(maxCapacity);} else {return PooledDirectByteBuf.newInstance(maxCapacity);} }
因为默认通常是有unsafe对象的, 所以这里会走到这一步中PooledUnsafeDirectByteBuf.newInstance(maxCapacity)
通过静态方法newInstance创建一个PooledUnsafeDirectByteBuf对象
跟到newInstance方法中:
static PooledUnsafeDirectByteBuf newInstance(int maxCapacity) {PooledUnsafeDirectByteBuf buf = RECYCLER.get();buf.reuse(maxCapacity);return buf; }
这里通过RECYCLER.get()这种方式拿到一个ByteBuf对象, RECYCLER其实是一个对象回收站, 这部分内容会在后面的内容中详细剖析, 这里我们只需要知道, 这种方式能从回收站中拿到一个对象, 如果回收站里没有相关对象, 则创建一个新
因为这里有可能是从回收站中拿出的一个对象, 所以通过reuse进行复用
跟到reuse方法中:
final void reuse(int maxCapacity) {maxCapacity(maxCapacity);setRefCnt(1);setIndex0(0, 0);discardMarks(); }
这里设置了的最大可扩容内存, 对象的引用数量, 读写指针位置都重置为0, 以及读写指针的位置标记也都重置为0
我们回到PoolArena的allocate方法中:
PooledByteBuf<T> allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) { PooledByteBuf<T> buf = newByteBuf(maxCapacity); allocate(cache, buf, reqCapacity);return buf; }
拿到了ByteBuf对象, 就可以通过allocate(cache, buf, reqCapacity)方法进行内存分配了
跟到allocate方法中:
private void allocate(PoolThreadCache cache, PooledByteBuf<T> buf, final int reqCapacity) {//规格化final int normCapacity = normalizeCapacity(reqCapacity);if (isTinyOrSmall(normCapacity)) { int tableIdx;PoolSubpage<T>[] table;//判断是不是tintyboolean tiny = isTiny(normCapacity);if (tiny) { // < 512//缓存分配if (cache.allocateTiny(this, buf, reqCapacity, normCapacity)) {return;}//通过tinyIdx拿到tableIdxtableIdx = tinyIdx(normCapacity);//subpage的数组table = tinySubpagePools;} else {if (cache.allocateSmall(this, buf, reqCapacity, normCapacity)) {return;}tableIdx = smallIdx(normCapacity);table = smallSubpagePools;}//拿到对应的节点final PoolSubpage<T> head = table[tableIdx];synchronized (head) {final PoolSubpage<T> s = head.next;//默认情况下, head的next也是自身if (s != head) {assert s.doNotDestroy && s.elemSize == normCapacity;long handle = s.allocate();assert handle >= 0;s.chunk.initBufWithSubpage(buf, handle, reqCapacity);if (tiny) {allocationsTiny.increment();} else {allocationsSmall.increment();}return;}}allocateNormal(buf, reqCapacity, normCapacity);return;}if (normCapacity <= chunkSize) {//首先在缓存上进行内存分配if (cache.allocateNormal(this, buf, reqCapacity, normCapacity)) {//分配成功, 返回return;}//分配不成功, 做实际的内存分配 allocateNormal(buf, reqCapacity, normCapacity);} else {//大于这个值, 就不在缓存上分配 allocateHuge(buf, reqCapacity);} }
这里看起来逻辑比较长, 其实主要步骤分为两步
1.首先在缓存上进行分配, 对应步骤是:
cache.allocateTiny(this, buf, reqCapacity, normCapacity)
cache.allocateSmall(this, buf, reqCapacity, normCapacity)
cache.allocateNormal(this, buf, reqCapacity, normCapacity)
2.如果在缓存上分配不成功, 则实际分配一块内存, 对应步骤是
allocateNormal(buf, reqCapacity, normCapacity)
在这里对几种类型的内存进行介绍:
之前的小节我们介绍过, 缓冲区内存类型分为tiny, small, 和normal, 其实还有种不常见的类型叫做huge, 那么这几种类型的内存有什么区别呢, 实际上这几种类型是按照缓冲区初始化空间的范围进行区分的, 具体区分如下:
tiny类型对应的缓冲区范围为0-512B
small类型对应的缓冲区范围为512B-8K
normal类型对应的缓冲区范围为8K-16MB
huge类型对应缓冲区范围为大于16MB
简单介绍下有关范围的含义:
16MB对应一个chunk, netty是以chunk为单位向操作系统申请内存的
8k对应一个page, page是将chunk切分后的结果, 一个chunk对应2048个page
8k以下对应一个subpage, subpage是page的切分, 一个page可以切分多个subpage, 具体切分几个需要根据subpage的大小而定, 比如只要分配1k的缓冲区, 则会将page切分成8个subpage
以上就是directArena内存分配的大概流程和相关概念
上一节: PooledByteBufAllocator简述
下一节: 命中缓存的分配
转载于:https://www.cnblogs.com/xiangnan6122/p/10205478.html
Netty源码分析第5章(ByteBuf)----第5节: directArena分配缓冲区概述相关推荐
- Netty源码分析第6章(解码器)----第4节: 分隔符解码器
Netty源码分析第6章(解码器)---->第4节: 分隔符解码器 Netty源码分析第六章: 解码器 第四节: 分隔符解码器 基于分隔符解码器DelimiterBasedFrameDecode ...
- Netty源码分析第7章(编码器和写数据)----第2节: MessageToByteEncoder
Netty源码分析第7章(编码器和写数据)---->第2节: MessageToByteEncoder Netty源码分析第七章: Netty源码分析 第二节: MessageToByteEnc ...
- Netty源码分析第1章(Netty启动流程)----第4节: 注册多路复用
Netty源码分析第1章(Netty启动流程)---->第4节: 注册多路复用 Netty源码分析第一章:Netty启动流程 第四节:注册多路复用 回顾下以上的小节, 我们知道了channe ...
- Netty源码分析系列之常用解码器(下)——LengthFieldBasedFrameDecoder
扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,Spring源码分析和Java并发编程文章. 前言 在上一篇文章中分析了三个比较简单的解码器,今天接着分析最后一个常用的解码器:Leng ...
- 【Netty源码分析摘录】(八)新连接的接入
文章目录 1.问题 2.检测新连接接入 3.创建客户端 channel 4. 绑定 NioEventLoop 4.1 register0 4.1.1 doRegister() 4.1.2 pipeli ...
- Netty源码分析(六)—Future和Promis分析
Netty源码分析(六)-Future和Promis分析 Future用来在异步执行中获取提前执行的结果 个人主页:tuzhenyu's page 原文地址:Netty源码分析(六)-Future和P ...
- Netty源码分析系列之服务端Channel的端口绑定
扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,Spring源码分析和Java并发编程文章. 微信公众号 问题 本文内容是接着前两篇文章写的,有兴趣的朋友可以先去阅读下两篇文章: Ne ...
- Netty 源码分析系列(十五)自定义解码器、编码器、编解码器
前言 我们今天继续来分析 Netty 的编解码器,这次我们要自己动手实现自定义的编码器.解码器和编解码器. 自定义基于换行的解码器 LineBasedFrameDecoder 类 LineBasedF ...
- netty源码分析系列——EventLoop
2019独角兽企业重金招聘Python工程师标准>>> 前言 EventLoop也是netty作为一个事件驱动架构的网络框架的重要组成部分,netty主要通过它来实现异步编程,从前面 ...
最新文章
- c语言的特点能够编制出复杂的功能程序,以下不是C语言的特点的是()
- cucumber_java从入门到精通(5)使用maven创建cucumber_java项目
- C语言基础_函数指针
- 运行时数据区(Run-Time Data Areas)
- 5.7 随机采样最小二乘法
- CVPR 2021 分布对齐,长尾分布问题解决新思路
- 每天两小时,吃透法国TOP双硕专家匠心打造的这套目标检测、卷积神经网络和OpenCV学习笔记(保姆级/20G高清/PPT/代码)...
- linux离线安装virtualen,在Virtualbox中安装PuppyLinux实录三
- 充分利用 UE4 中的噪声
- SQL SERVER 2008的top增强
- DBeaver 连接 Oracle
- Qt+STK项目配置
- 思科交换机关闭服务端口
- Centos 7 mysql 数据库安装和配置
- matlab程序中ode45,关于matlab中ode45的问题
- 2018年第九届蓝桥杯A组省赛
- spring-IOC原理详解
- T-3.2-把Redis当作消息队列合不合适
- nextcloud安装日历插件使用并设置导入导出和云端同步(安卓手机和ios手机)
- 10大网络美女排行榜(组图)(*^__^*) ……
热门文章
- EFLS开源 | 阿里妈妈联邦学习解决方案详解
- 取木棒21根c语言,关于m根火柴 ,人机最多取n根火柴(21根火柴进阶)
- oracle分区和锁的难,oracle使用三(锁和表分区)
- pymysql安装_第八章 nova组件安装2
- android framework,GitHub - zhaozepeng/Android_framework: android framework 用来快速开发的android框架...
- jenkins docker 自动部署 构建_jenkins+docker+vue项目的自动部署环境
- Docker: vmware企业级docker镜像私服--Harbor的搭建
- 【IT笔试面试题整理】二叉树中和为某一值的路径--所有可能路径
- linux TCP/IP L2层数据包接收流程,eth_rxnetif_receive_skb处理流程
- 缴纳满15年养老保险退休金每月1200块钱左右,值得缴吗?