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.pswp.cn/news/537285.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/537285.shtml
英文地址,請注明出處:http://en.pswp.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”指鄉鎮(街道)基…

spring boot——MockMvc的用法

1.pom配置 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId> </dependency> 2.所需對象及Controller public class User {private String id;private String username;private…

python一元加號_Python一元方程解算系統(需要Sympy庫支持)

解算案例本文為實現python一元方程解算的源碼案例(后續不定期更新)# -*- coding: UTF-8 -*-from sympy import *#設置一些可能拋出的異常def Warn(type):if type "missEquater":print "You missed the euqater!"elif type "excessiveEquater":…

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

很多淘寶商家在直播前沒有做淘寶直播預告&#xff0c;或者不知道怎么去做直播預告&#xff0c;這對直播的效果會有很大的影響&#xff0c;那么直播前如何做好直播預告呢?怎樣的直播預告才是合格的&#xff0c;下面來了解一下。1.必須去淘寶直播中控臺發布。因為手機上發布目前…

“1+7+N”改革工作體系介紹

2021年&#xff0c;浙江省確定了“17N”的改革工作體系&#xff0c;要求以全面深化改革新成效再創體制機制新優勢。&#xff08;2022年已經升級為“1612N”&#xff0c;點擊閱讀&#xff09; “1” 數字化改革&#xff0c;這是浙江全面深化改革的總抓手。將聚焦打造全球數字變…

傻傻分不清的javascript運行機制

學習到javascript的運行機制時&#xff0c;有幾個概念經常出現在各種文章中且容易混淆。Execution Context(執行環境或執行上下文)&#xff0c;Context Stack (執行棧)&#xff0c;Variable Object(VO: 變量對象)&#xff0c;Active Object(AO: 活動對象)&#xff0c;LexicalEn…

浙江省數字化改革回顧(2022年5月)

事業的偉大在于目標的壯麗&#xff0c;也在于過程的壯麗&#xff1b;改革的成果在于享有的豐富&#xff0c;也在于經歷的豐富。2021年2月18日&#xff0c;春節假期后首個工作日&#xff0c;浙江省委召開全省數字化改革大會&#xff0c;在全國率先開啟數字化改革探索實踐。此后&…

python 某個數是不是在某個范圍內_教寫一個簡單的python小程序(04)

點擊藍字關注我們 會酸的柚子Python愛好者搞機少年七夕結束了~酸柚也是被強塞了滿嘴的狗糧在這樣充滿戀愛腐朽氣息的一天酸柚也是馬不停蹄的在趕稿子兄弟們&#xff0c;給我頂起來呀~我們來看看今日的題目可能很多小伙伴對完全平方數這個概念有點生疏了完全平方數數學上&#x…

Python:模塊module

python中一個模塊就是一個擴展名為.py的文件&#xff0c;也可能是預編譯的.pyc文件。 引入模塊用&#xff1a;import 模塊名 使用引用模塊中定義的標識符&#xff08;函數、變量、類&#xff09;用&#xff1a;模塊名.標識符名 引入模塊中的標識符用&#xff1a;from 模塊名 im…

浙江公布2022年數字化改革“最系列“成果 評選出最佳應用104項

10月29日&#xff0c;省委改革辦&#xff08;省數改辦&#xff09;公布了2022年數字化改革“最系列”成果。該評選由省委改革辦&#xff08;省數改辦&#xff09;會同省委政研室、省人大常委會法工委、省市場監管局和省大數據局共同開展&#xff0c;評選了最佳應用104項、最強大…

dot net core 使用 IPC 進程通信

原文:dot net core 使用 IPC 進程通信版權聲明&#xff1a;博客已遷移到 http://lindexi.gitee.io 歡迎訪問。如果當前博客圖片看不到&#xff0c;請到 http://lindexi.gitee.io 訪問博客。本文地址 https://blog.csdn.net/lindexi_gd/article/details/79946496 dot net core 使…

python可變類型和不可變深淺拷貝類型_python3筆記十四:python可變與不可變數據類型+深淺拷貝...

一&#xff1a;學習內容python3中六種數據類型python賦值python淺拷貝python深拷貝二&#xff1a;python3六種數據類型1.六種數據類型Number(數字)string(字符串)List(列表)Tuple(元祖)Set(集合)Dictionary(字典)2.六種數據類型分類不可變數據(3個)&#xff1a;Number、String、…

Android手機用wifi連接adb調試的方法

https://www.jianshu.com/p/dc6898380e38 0x0 前言 Android開發肯定要連接pc的adb進行調試&#xff0c;傳統的方法是用usb與pc進行連接&#xff0c;操作簡單即插即用&#xff0c;缺點是pc上必須得有對應手機的usb驅動程序&#xff0c;對于谷歌親兒子系列和三星摩托等外國品牌而…

控制臺應用程序換換為窗體應用_Epic為開發者設計了一套iPhone使用的運動捕捉應用程序...

玩懂手機網7月13日資訊&#xff0c;我們都知道對于游戲或者是動漫開發者來說&#xff0c;運動捕捉設備是一套非常昂貴的設備&#xff0c;需要非常專業的獨立開發人員&#xff0c;大量的時間才能完成&#xff0c;最近Epic為開發者設計了一套iPhone使用的運動捕捉應用程序。這套i…

螞蟻金服億級并發下的移動端到端網絡接入架構解析

為了與金融從業者、科技從業者共同探討金融 業務的深層次問題&#xff0c;螞蟻金服聯手 TGO 鯤鵬會上海分會&#xff0c;在 12 月 8 日舉辦了「走進螞蟻金服&#xff1a;雙十一背后的螞蟻金服技術支持」活動。螞蟻金服高級技術專家賈島為大家分享了《億級并發下的螞蟻移動端到…

python3.12答案_編程常見問題

通常&#xff0c;不要使用 from modulename import * 。這樣做會使導入器的命名空間變得混亂&#xff0c;并且使得連接器更難以檢測未定義的名稱。在文件的頂部導入模塊。這樣做可以清楚地了解代碼所需的其他模塊&#xff0c;并避免了模塊名稱是否在范圍內的問題。每行導入一個…