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简述

下一节: 命中缓存的分配

posted on 2019-01-01 18:32 向南是个万人迷 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/xiangnan6122/p/10205478.html

Netty源码分析第5章(ByteBuf)----第5节: directArena分配缓冲区概述相关推荐

  1. Netty源码分析第6章(解码器)----第4节: 分隔符解码器

    Netty源码分析第6章(解码器)---->第4节: 分隔符解码器 Netty源码分析第六章: 解码器 第四节: 分隔符解码器 基于分隔符解码器DelimiterBasedFrameDecode ...

  2. Netty源码分析第7章(编码器和写数据)----第2节: MessageToByteEncoder

    Netty源码分析第7章(编码器和写数据)---->第2节: MessageToByteEncoder Netty源码分析第七章: Netty源码分析 第二节: MessageToByteEnc ...

  3. Netty源码分析第1章(Netty启动流程)----第4节: 注册多路复用

    Netty源码分析第1章(Netty启动流程)---->第4节: 注册多路复用 Netty源码分析第一章:Netty启动流程   第四节:注册多路复用 回顾下以上的小节, 我们知道了channe ...

  4. Netty源码分析系列之常用解码器(下)——LengthFieldBasedFrameDecoder

    扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,Spring源码分析和Java并发编程文章. 前言 在上一篇文章中分析了三个比较简单的解码器,今天接着分析最后一个常用的解码器:Leng ...

  5. 【Netty源码分析摘录】(八)新连接的接入

    文章目录 1.问题 2.检测新连接接入 3.创建客户端 channel 4. 绑定 NioEventLoop 4.1 register0 4.1.1 doRegister() 4.1.2 pipeli ...

  6. Netty源码分析(六)—Future和Promis分析

    Netty源码分析(六)-Future和Promis分析 Future用来在异步执行中获取提前执行的结果 个人主页:tuzhenyu's page 原文地址:Netty源码分析(六)-Future和P ...

  7. Netty源码分析系列之服务端Channel的端口绑定

    扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,Spring源码分析和Java并发编程文章. 微信公众号 问题 本文内容是接着前两篇文章写的,有兴趣的朋友可以先去阅读下两篇文章: Ne ...

  8. Netty 源码分析系列(十五)自定义解码器、编码器、编解码器

    前言 我们今天继续来分析 Netty 的编解码器,这次我们要自己动手实现自定义的编码器.解码器和编解码器. 自定义基于换行的解码器 LineBasedFrameDecoder 类 LineBasedF ...

  9. netty源码分析系列——EventLoop

    2019独角兽企业重金招聘Python工程师标准>>> 前言 EventLoop也是netty作为一个事件驱动架构的网络框架的重要组成部分,netty主要通过它来实现异步编程,从前面 ...

最新文章

  1. c语言的特点能够编制出复杂的功能程序,以下不是C语言的特点的是()
  2. cucumber_java从入门到精通(5)使用maven创建cucumber_java项目
  3. C语言基础_函数指针
  4. 运行时数据区(Run-Time Data Areas)
  5. 5.7 随机采样最小二乘法
  6. CVPR 2021 分布对齐,长尾分布问题解决新思路
  7. 每天两小时,吃透法国TOP双硕专家匠心打造的这套目标检测、卷积神经网络和OpenCV学习笔记(保姆级/20G高清/PPT/代码)...
  8. linux离线安装virtualen,在Virtualbox中安装PuppyLinux实录三
  9. 充分利用 UE4 中的噪声
  10. SQL SERVER 2008的top增强
  11. DBeaver 连接 Oracle
  12. Qt+STK项目配置
  13. 思科交换机关闭服务端口
  14. Centos 7 mysql 数据库安装和配置
  15. matlab程序中ode45,关于matlab中ode45的问题
  16. 2018年第九届蓝桥杯A组省赛
  17. spring-IOC原理详解
  18. T-3.2-把Redis当作消息队列合不合适
  19. nextcloud安装日历插件使用并设置导入导出和云端同步(安卓手机和ios手机)
  20. 10大网络美女排行榜(组图)(*^__^*) ……

热门文章

  1. EFLS开源 | 阿里妈妈联邦学习解决方案详解
  2. 取木棒21根c语言,关于m根火柴 ,人机最多取n根火柴(21根火柴进阶)
  3. oracle分区和锁的难,oracle使用三(锁和表分区)
  4. pymysql安装_第八章 nova组件安装2
  5. android framework,GitHub - zhaozepeng/Android_framework: android framework 用来快速开发的android框架...
  6. jenkins docker 自动部署 构建_jenkins+docker+vue项目的自动部署环境
  7. Docker: vmware企业级docker镜像私服--Harbor的搭建
  8. 【IT笔试面试题整理】二叉树中和为某一值的路径--所有可能路径
  9. linux TCP/IP L2层数据包接收流程,eth_rxnetif_receive_skb处理流程
  10. 缴纳满15年养老保险退休金每月1200块钱左右,值得缴吗?