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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

uni-app(从零开始)

uni-app&#xff08;从零开始&#xff09; uni-app 是什么&#xff1f; uniapp 就是使用Vue.js技术开发所有前端框架的跨端框架uniapp 就是可以将一套代码 发布到多个平台 uniapp 和 Vue 的关系&#xff1f; uniapp是基于vue进行开发&#xff0c;继承了Vue的特性和语法在开…

Remote desktop manager共享账号

因为多个远程机器&#xff0c;是会用了域账号进行登录的。而域账号的密码&#xff0c;三个月之后&#xff0c;密码强制过期 添加一个新的entry&#xff0c;类型是Credential Entry&#xff0c;然后选择用户名/密码 在remote desktop编辑的页面&#xff0c;Credentials选择Crede…

bzoj4403:序列统计

我好傻啊 题目 先来看看长度只能为\(n\)的情况 那么答案非常显然是\(\binom{mn-1}{n}\) 其中\(mR-L1\) 因为我们要构造一个非降序列&#xff0c;显然可能一个数会被选择多次&#xff0c;组合非常不好做&#xff0c;于是我们可以把每一个数的下标加上其对应的下标那么现在的值域…

Mui常用的方法

中对话框 语法&#xff1a;mui.confirm 用法 mui.confirm("确认要切换角色&#xff1f;", "提示", btnArray, function(e) {if(e.index 1) {} else {}});组件名作用alert警告框confirm确认框prompt输入对话框toast消息提示框&#xff08;自动消失&#x…

sudo: pip:找不到命令

https://blog.csdn.net/fcku_88/article/details/84191288转载于:https://www.cnblogs.com/xxswkl/p/11012709.html

java ListMapString,Object遍历的方法

java List<Map<String,Object>遍历的方法 public class Test {public static void main(String[] args) {List<Map<String, Object>> listMaps new ArrayList<Map<String, Object>>();Map<String, Object> map1 new HashMap<Strin…

vue如何更换网页标签的logo

Vue2 版本更换图标 在我们项目的根目录下面去添加或者替换 favicon.icon文件 找到我们的 build 文件夹下面的这两个文件 进行如下配置 favicon: resolveApp(’./favicon.ico’) 刷新后发现并没有什么效果 莫慌 最后一步 重启项目 改变端口 如果重启后还没有起到作用的话就…

Java并发编程的艺术(十)——Java中的锁(5)

1. LockSupport工具 1.1 LockSupport的作用 当需要阻塞或唤醒一个线程的时候&#xff0c;都会使用LockSupport工具类来完成相应工作。LockSupport定义了一组公共的静态方法&#xff0c;这些方法提供了做基本的线程阻塞和唤醒功能。 1.2 LockSupport提供的阻塞和唤醒方法 方法描…

运动-模拟返回顶部

第一步&#xff1a;获取底部的那个按钮对象&#xff0c;默认的情况下那个按钮对象是不可见的。可见的条件的是滚轮距离顶部有距离。 var oBtndocument.getElementById(btn1); 第二步&#xff1a;添加滚轮事件。 (1). 获取滚轮距离顶部的距离。如果距离大于0&#xff0c;就将按钮…

《JavaScript高级程序设计》笔记总结

在北京上班的我每天在上下班路上的时间总共是两个半小时&#xff0c;为了充实这两个多小时的时间&#xff0c;我便花了银子换得了下面这个宝贝 本书内容&#xff08;引用书中前言&#xff09; 本书提供了JavaScript开发人员必须掌握的内容&#xff0c;全面涵盖了JavaScript的…

Task执行多次

项目中&#xff0c;曾经出现过启动时数据库连接数瞬间增大&#xff0c;当时并没有注意该问题。 后期&#xff0c;由于Task任务多次执行&#xff0c;才着手查看这个问题&#xff0c;经排查&#xff0c;由于tomcat中webapp配置多次&#xff0c;导致webapp被扫描多次&#xff08;配…

ES6 的新特性总结

ES6 的新特性总结 关于声明变量 由 var 变成 let 和 const 区别&#xff1a; var声明的变量会挂载到window上&#xff0c;let和const声明的变量不会var声明的变量存在变量提升&#xff0c;而let和const声明的变量不存在变量提升let和const声明的变量形成块级作用域在同一作…

递推(一):递推法的基本思想

所谓递推&#xff0c;是指从已知的初始条件出发&#xff0c;依据某种递推关系&#xff0c;逐次推出所要求的各中间结果及最后结果。其中初始条件或是问题本身已经给定&#xff0c;或是通过对问题的分析与化简后确定。 利用递推算法求问题规模为n的解的基本思想是&#xff1a;当…

在vue中methods互相调用的方法

在vue中methods互相调用的方法 转载于:https://www.cnblogs.com/macT/p/10212878.html

MUI H5+ 开发app基础

加载子页面(防止手机性能差,出现上下滑动卡顿) 其中 url 就是子页面的路径 id 为自定义 通常和页面名称一致页面的跳转和传值 切记 如果使用mui组件内的底部导航跳转的方式只能使用document获取元素的id 页面跳转传值 新页面接收参数 页面初始化 H5加载完毕 判断某个元素中是…

对象

一、对象 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title><script type"text/javascript">/** JS中数据类型* String 字符串* Number 数值* Boolean 布尔值* Null 空值* Undefine…

uni-app 组件传值

uni-app中的组件之间的传值 我们将compontents中的test文件作为子组件 引入到index中使用 引入并使用 效果如下 父传子 首先我们在父组件中使用子组件的标签中去自定义title 在子组件中 通过props去接收并处理 效果如下&#xff1a; 子传父 子组件中 设置一个按钮…

JSP XML数据处理

JSP XML数据处理 当通过HTTP发送XML数据时&#xff0c;就有必要使用JSP来处理传入和流出的XML文档了&#xff0c;比如RSS文档。作为一个XML文档&#xff0c;它仅仅只是一堆文本而已&#xff0c;使用JSP创建XML文档并不比创建一个HTML文档难。 使用JSP发送XML 使用JSP发送XML内容…

Docker 图形界面管理工具 -- Portainer

Portainer&#xff08;基于 Go&#xff09;是一个轻量级的管理界面&#xff0c;可让您轻松管理Docker主机或Swarm集群。 Portainer的使用意图是简单部署。它包含可以在任何 Docker 引擎上运行的单个容器&#xff08;Docker for Linux 和 Docker for Windows&#xff09;。 Port…

vue cli3.0创项目报错‘This may cause things to work incorrectly. Make sure to use the same version for b’

错误&#xff1a; throw new Error(^Error:Vue packages version mismatch:- vue2.6.12 (C:\Users\Administrator\AppData\Roaming\npm\node_modules\vue\dist\vue.runtime.common.js) - vue-template-compiler2.6.11 (C:\Users\Administrator\AppData\Roaming\npm\node_module…