netty发送数据_看完这篇还不清楚Netty的内存管理,那我就哭了

说明

在学习Netty的时候,ByteBuf随处可见,但是如何高效分配ByteBuf还是很复杂的,Netty的池化内存分配这块还是比较难的,很多人学习过,看过但是还是云里雾里的,本篇文章就是主要来讲解:Netty分配池化的堆外内存的细节,期待可以让你明白!!!

由于为了更好的表达,文章中的图我最少画了6小时,画的不熟悉,并且也强调一些细节上。

ByteBuf重要性

ByteBuf在Netty中一直存在,读写必备!ByteBuf是Netty的数据容器,高效分配ByteBuf至关重要!

72bc6a0f187051265b8c0715898c8a17.png

Netty从socket读取数据。

1f08a96af346a71950275966b937d591.png

Netty准备把数据写到socket中去。

24f80ff393773bfcf000231314c19c4a.png

通过这里我们就可以看到,再把数据写socket的之前会判断是否是堆外内存,如果不是会构造一个directbuffer对象的,细节代码如下:

if (msg instanceof ByteBuf) { ByteBuf buf = (ByteBuf) msg; if (buf.isDirect()) { return msg; } return newDirectBuffer(buf); }
6eed64f1a67f5183ec12d9b5e563f8e7.png

所以本篇文章就是主要来讲解:Netty分配池化的堆外内存的细节,其实分配堆内存的细节很多也是类似的。

备注: 为什么不是堆外内存还要转堆外内存,为什么加这个判断,我之前也不理解,忽然有天和涤生大佬讨论,讨论讨论就清晰了,后续有空写篇。

总览

80e6a142780775a517eea516aa71245f.png

本次主要讨论的是关于池化内存的分配,PooledByteBufAllocator就是netty分配池化内存的操作入口。

其提供对外常用操作api:

c9b20a585377ad4bc8a6904d1ffa32a6.png

Netty在发送数据的时候会判断是否是堆外内存,如果不是会进行封装的:

3954554038e8ecdc6bd141f9b50eeb9e.png

所有这里我们以分配池化的堆外内存为例,进行本文说明。池化的堆内存分配其实流程都差不多的。

下面我们来看看分配示例demo:

public static void main(String[] args) { ByteBufAllocator alloc = PooledByteBufAllocator.DEFAULT; //tiny规格内存分配 会变成大于等于16的整数倍的数:这里254 会规格化为256 ByteBuf byteBuf = alloc.directBuffer(254); //读写bytebuf byteBuf.writeInt(126); System.out.println(byteBuf.readInt()); //很重要,内存释放 byteBuf.release();}

后续我们都会根据这段简单的demo进行分析。

操作入口类

PooledByteBufAllocator的初始化:

dba7852be59a003acc10dbe9b2ec3bf9.png

进去之后可以看到核心类的一初始化操作:

222489e3ea1627e82bac857bddff8d1e.png
d82d87b4263f7baccb267ef29b1cb5d9.png
5d3da4948cceab2208328f413c0aa1e6.png

分配理论是jemalloc,可以理解为java版本的jemalloc实现。

PoolThreadCache

4eda3b6b6e6ad565e61a22fb069c309a.png

通过上图可以清晰的了解到PoolThreadCache的主要数据结构。

开始的时候,这些Cache里面都是没有值的,只有在调用free释放的时候(在后续释放内存中会讲解),才会把之前分配的内存大小放到该cache的queue里面,其实每次分配的时候都是先看看是否缓存里面有,如果有直接返回,没有则进行正常的分配流程(内存分配会讲解)。

我们来看看PoolArena directArena内容:

bd09e671c1ab0815afc16ddc3ba1d31a.png

下面我们来看看PoolArena结构。

PoolArena

4c8719798cc973e401db741a06fcb5af.png

通过下图可以清晰的了解到PoolArena的主要数据结构。

a505d42ada501d6f3ba6c805fd9973d0.png

在PoolArena里面涉及到PoolChunkList和PoolSubpage对应的结构有PoolChunk和PoolSubpage,我们来详细的看看这2块内容。

PoolChunk

第一次的时候,PoolChunkList、PoolSubpage都是默认值,需要新增一个Chunk,默认一个Chunk是16M。内部会结构是完全二叉树一共有4096个节点,有2048个叶子节点(每个叶子节点大小为一个page,就是8k),非叶子节点的内存大小等于左子树内存大小加上右子树内存大小。

完全二叉树结构如下:

c6ffdf85ed1d2db59fdd2d5bb1258182.png

这颗完全二叉树在java中是使用数组来进行表示的。

唯一需要注意的是,下标是从1开始而不是0.

07b26dcfdff5f3865c42978ac17ddafb.png

depthMap的值初始化后不再改变,memoryMap的值则随着节点分配而改变。

77049efc160524e07ae82d484376d145.png

这个值太多就不都截图了,就是把上面那颗完全二叉树用数组表示了而已,只是值存的不是节点的下标而是存的树的深度而已。

depthMap数组值为0表示可以分配16M空间,如果为1 表示可以分配8M,,如果为2表示嗯可以分配4M,如果为3表示可以分配2M ……………………如果为11表示可以分配8k空间。

如果该节点已经分配完成,就设置为12即可。

怎么确定需要分配的大小在深度是多少?

如果需要分配的内存规格化之后,是小于8k,那么在8k上面分配即可(即深度为11)。

如果为8k或者大于8k那么通过下面代码就可以定位到深度了:

int d = maxOrder - (log2(normCapacity) - pageShifts);

知道深度之后,怎么进行定位到那个节点呢???

e0a4681b44caf88c053ce47b77515d06.png

找到该节点之后,先把该节点显示占用,在更新起父节点父节点的父………………如下:

4782fbb9f9b849a41597113d24ce07ec.png

SubpagePool

64f1803c4a858a300fffd6e454a25f8e.png

上面的图就是关于SubpagePool的内存结构了。我们在分配page的时候,根据memoryMap对于的值就知道是否被分配了,那么如果是subpagePool呢?

subpagePool分为2类:tinySubpagePools和smallSubpagePools,大小对于也对于上面的图里面了,每类都是固定大小的,如果分配256b的大小,那么一个page就是8k,8*1024/256 = 32块。那么怎么怎么表示每个还被分配了呢?

private final long[] bitmap;

由于一个long占用的字节数为64,我们这里仅仅是需要表示32个,所以使用一个long即可了,二进制每位 1表示已经使用了,0表示还未使用。

132fbb1fb264f287f3b2eae27aec0bb6.png

由于subpage不仅仅需要定位到完全二叉树在那个节点,还需要知道在long的第几个 并且是第几位,所以要复杂一些:

c68270cca1f248266d61c9d443763b7a.png

通过一个long的前32位来表示subpage的第几个long的第几位上面,通过后32来表示在完全二叉树的那个

分配核心

分配入口:ByteBuf byteBuf = alloc.directBuffer(256);

进行跟进代码:

0fdc37d098a852bd7756367e8f927c72.png

我们来看:PooledByteBuf buf = newByteBuf(maxCapacity);

构建PooledByteBuf对象。最后返回PooledByteBuf对象。

我们来看下类继承结构:

b4e00445a91c08d2edf6655ae4e86a63.png

所有ByteBuf byteBuf = alloc.directBuffer(256);这句话是没有什么问题的,不会报错。

我们来看看newByteBuf(maxCapacity)的细节实现:

b4777ed0ba124cc186132e54762a2b25.png

这里借助了Netty增加实现的Recycler对象池技术。Recycler设计也非常精巧,后续可以专门写篇Recycler文章,今天不是重点,我们只要知道由于分配PolledByteBuf对象的代价有点大,如果需要频繁使用到PolledByteBuf对象,并且对性能有所要求,那么池化技术是一个不错的选择(比如我们以前使用的线程池、数据库连接池等都是类似道理),池化技术在一定程度上面减少了频繁创建对象带来的性能开销。其实这个类似的思想非常常见(比如我们查询数据库成本高,缓存到redis,思路也是一样的),在本篇后续中还可以体会到(PoolThreadCache)。

通过PooledByteBuf buf = newByteBuf(maxCapacity);仅仅是获取到了一个初始对象而已。

分配的核心在:allocate(cache, buf, reqCapacity);

b98fdd6c4dc0c3d8aa6e089e4b458800.png
  • 先尝试在1步骤 进行分配,根据不同的类型定位到不同的Caches,如果有进行分配直接返回。
  • 如果1步骤 分配不了,进行2步骤上面分配。

2步骤分配细节:看看需要分配的是什么类型 page还是subpage,如果是subpage在根据看看是tinySubpagePools还是smallSubpagePools,找到对应的槽位,看看链表里是否有可用的PoolSubpage,如果有就进行分配修改标记退出,如果没有就现需要在先分配一个page了,根据chunklist的这些看看是否有合适的,如果有合适的,那么在这些已经有的chunk上面进行分配一个page (分配page也是这个情况了)

之后在根据分配到的page,进行该请求大小的分配 (由于一个page可以存储很多同大小的数量)需要用long的位标记,表示该位置分配了,并且修改完全二叉树的父等值,分配结束。如果没有chunk那么需要新分配一块chunk之后重复上面步骤即可。

释放核心

释放入口 :byteBuf.release();

进行跟进代码:

3633ae98ebf0317916de49eb9dbbd0be.png
5d3911c7a617f5a17e4a464b2aee3a7f.png
3d68b7ea4a998c0323a5cfdf28cf018c.png

通过这段代码我们就这段放入到相应的queue了:

b98aaea416257bcdb5d9c32b05d29b93.png

缓存到了对应的Cache的queue里面了。

文章来源:https://dwz.cn/ESnnz4zJ

作者:零度冰炫

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

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

相关文章

数字化改革体系架构“152”两次迭代升级为“1612”

数字化改革体系架构已经完成两次迭代,152-1512-1612。 2021年,浙江在全国率先启动一项关系全局、影响深远、制胜未来的重大集成改革——数字化改革,并确定为全面深化改革的总抓手。 2021年2月18日,数字化改革大会“152”工作体系…

python 40位的数减个位数_Python数据分析入门教程(五):数据运算

作者 | CDA数据分析师进行到这一步就可以算是开始正式的烹饪了,在这部分之前的数据操作部分我们列举了一些不同维度的分析指标,这一章我们主要看看这些指标都是怎么计算出来的。一、算术运算算术运算就是基本的加减乘除,在Excel或者Python中数…

数字化改革“152”体系详解

架构图 “1” 即一体化智能化公共数据平台(平台大脑),按照“统一规划、统一支撑、统一架构、统一平台、统一标准、统一建设、统一管理、统一运维"的要求,建设省市县三级公共数据平台,叠加三级“大脑功能&#xf…

数字化改革“141”体系

县级以上是“152”大框架,县以下是“141”体系。 141体系是:县级社会治理中心、乡镇(街道)基层治理“四个平台”、村社网格。 “1” 第一个“1”指县级社会治理中心。 “4” 第二个“4”指乡镇(街道)基…

接口做的好怎么形容_淘宝直播预告怎么做才合格?如何做好?

很多淘宝商家在直播前没有做淘宝直播预告,或者不知道怎么去做直播预告,这对直播的效果会有很大的影响,那么直播前如何做好直播预告呢?怎样的直播预告才是合格的,下面来了解一下。1.必须去淘宝直播中控台发布。因为手机上发布目前…

“1+7+N”改革工作体系介绍

2021年,浙江省确定了“17N”的改革工作体系,要求以全面深化改革新成效再创体制机制新优势。(2022年已经升级为“1612N”,点击阅读) “1” 数字化改革,这是浙江全面深化改革的总抓手。将聚焦打造全球数字变…

浙江省数字化改革回顾(2022年5月)

事业的伟大在于目标的壮丽,也在于过程的壮丽;改革的成果在于享有的丰富,也在于经历的丰富。2021年2月18日,春节假期后首个工作日,浙江省委召开全省数字化改革大会,在全国率先开启数字化改革探索实践。此后&…

python 某个数是不是在某个范围内_教写一个简单的python小程序(04)

点击蓝字关注我们 会酸的柚子Python爱好者搞机少年七夕结束了~酸柚也是被强塞了满嘴的狗粮在这样充满恋爱腐朽气息的一天酸柚也是马不停蹄的在赶稿子兄弟们,给我顶起来呀~我们来看看今日的题目可能很多小伙伴对完全平方数这个概念有点生疏了完全平方数数学上&#x…

浙江公布2022年数字化改革“最系列“成果 评选出最佳应用104项

10月29日,省委改革办(省数改办)公布了2022年数字化改革“最系列”成果。该评选由省委改革办(省数改办)会同省委政研室、省人大常委会法工委、省市场监管局和省大数据局共同开展,评选了最佳应用104项、最强大…

dot net core 使用 IPC 进程通信

原文:dot net core 使用 IPC 进程通信版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问。如果当前博客图片看不到,请到 http://lindexi.gitee.io 访问博客。本文地址 https://blog.csdn.net/lindexi_gd/article/details/79946496 dot net core 使…

Android手机用wifi连接adb调试的方法

https://www.jianshu.com/p/dc6898380e38 0x0 前言 Android开发肯定要连接pc的adb进行调试,传统的方法是用usb与pc进行连接,操作简单即插即用,缺点是pc上必须得有对应手机的usb驱动程序,对于谷歌亲儿子系列和三星摩托等外国品牌而…

控制台应用程序换换为窗体应用_Epic为开发者设计了一套iPhone使用的运动捕捉应用程序...

玩懂手机网7月13日资讯,我们都知道对于游戏或者是动漫开发者来说,运动捕捉设备是一套非常昂贵的设备,需要非常专业的独立开发人员,大量的时间才能完成,最近Epic为开发者设计了一套iPhone使用的运动捕捉应用程序。这套i…

蚂蚁金服亿级并发下的移动端到端网络接入架构解析

为了与金融从业者、科技从业者共同探讨金融 业务的深层次问题,蚂蚁金服联手 TGO 鲲鹏会上海分会,在 12 月 8 日举办了「走进蚂蚁金服:双十一背后的蚂蚁金服技术支持」活动。蚂蚁金服高级技术专家贾岛为大家分享了《亿级并发下的蚂蚁移动端到…

如何根据视频的宽屏与竖屏来排序?

原理 宽屏与竖屏是根据 帧高度 与 帧宽度 来区分的 帧高度就是图片高度(纵向的像素尺寸),帧宽度就是图片宽度(横向的像素尺寸),分辨率就是(高度x宽度)。 windows11的文件排序&…

sap模块介绍_小迈说|SAP究竟有多少模块?

SAP究竟有哪些模块继上一期小迈说SAP!SPA?的区别,相信大部分读者明白了我们与水浴按摩行业的分别,可是仅仅区分名字还不够,SAP还有众多的模块,这些又该怎么去了解呢?这就轮到肩负爱与责任的小迈…

360 再次开源管理平台 Wayne:基于企业级 Kubernetes 集群

2019独角兽企业重金招聘Python工程师标准>>> 奇虎 360 宣布正式开源 Wayne ,这是一个由 360 搜索云平台团队开发的通用的、基于 Web 的 Kubernetes 多集群一站式可视化管理平台。内置了丰富多样的功能,满足企业的通用需求,同时插件…

Node.js 根本没有这样搞性能优化的?

1、使用最新版本的 Node.js 仅仅是简单的升级 Node.js 版本就可以轻松地获得性能提升,因为几乎任何新版本的 Node.js 都会比老版本性能更好,为什么? Node.js 每个版本的性能提升主要来自于两个方面: V8 的版本更新;Nod…

可交付成果、核实的可交付成果、验收的可交付成果?

①可交付成果。指的是在某一过程、阶段或项目完成时,产出的任何独特并可核实的产品、成果或服务。可交付成果可能是有形的,也可能是无形的。【研发完成】 ②核实的可交付成果。是指已经完成,并经过“控制质量”过程检查为正确的可交付成果。…

安装oracle到create inventory时卡住了怎么办_win10系统安装教程(官方工具)

Hi,大家好。对于小白用户,装系统是比较头疼的事,所以今天写一个简单易懂的装系统教程。使用微软官方提供的工具制作U盘启动盘,操作简单,系统纯净,强烈建议小白用户使用。缺点是该工具功能单一,并…