成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

看完這篇還不清楚Netty的內存管理,那我就哭了!

開發 后端
在學習Netty的時候,ByteBuf隨處可見,但是如何高效分配ByteBuf還是很復雜的,Netty的池化內存分配這塊還是比較難的,很多人學習過,看過但是還是云里霧里的,本篇文章就是主要來講解:Netty分配池化的堆外內存的細節,期待可以讓你明白!??!

說明

在學習Netty的時候,ByteBuf隨處可見,但是如何高效分配ByteBuf還是很復雜的,Netty的池化內存分配這塊還是比較難的,很多人學習過,看過但是還是云里霧里的,本篇文章就是主要來講解:Netty分配池化的堆外內存的細節,期待可以讓你明白!!!

由于為了更好的表達,文章中的圖我最少畫了6小時,畫的不熟悉,并且也強調一些細節上。

由于該源碼中涉及到大量的二進制操作,建議看看其他二進制文章。

ByteBuf重要性

ByteBuf在Netty中一直存在,讀寫必備!ByteBuf是Netty的數據容器,高效分配ByteBuf至關重要!

看完這篇還不清楚Netty的內存管理,那我就哭了

Netty從socket讀取數據。

看完這篇還不清楚Netty的內存管理,那我就哭了

Netty準備把數據寫到socket中去。

看完這篇還不清楚Netty的內存管理,那我就哭了

通過這里我們就可以看到,再把數據寫socket的之前會判斷是否是堆外內存,如果不是會構造一個directbuffer對象的,細節代碼如下:

看完這篇還不清楚Netty的內存管理,那我就哭了


看完這篇還不清楚Netty的內存管理,那我就哭了

所以本篇文章就是主要來講解:Netty分配池化的堆外內存的細節,其實分配堆內存的細節很多也是類似的。

備注: 為什么不是堆外內存還要轉堆外內存,為什么加這個判斷,我之前也不理解,忽然有天和滌生大佬討論,討論討論就清晰了,后續有空寫篇。

看完這篇還不清楚Netty的內存管理,那我就哭了

本次主要討論的是關于池化內存的分配,PooledByteBufAllocator就是netty分配池化內存的操作入口。

其提供對外常用操作api:

看完這篇還不清楚Netty的內存管理,那我就哭了

Netty在發送數據的時候會判斷是否是堆外內存,如果不是會進行封裝的:

看完這篇還不清楚Netty的內存管理,那我就哭了

所有這里我們以分配池化的堆外內存為例,進行本文說明。池化的堆內存分配其實流程都差不多的。

下面我們來看看分配示例demo:

看完這篇還不清楚Netty的內存管理,那我就哭了

后續我們都會根據這段簡單的demo進行分析。

操作入口類

PooledByteBufAllocator的初始化:

看完這篇還不清楚Netty的內存管理,那我就哭了

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

看完這篇還不清楚Netty的內存管理,那我就哭了

 

 

看完這篇還不清楚Netty的內存管理,那我就哭了

 

 

 看完這篇還不清楚Netty的內存管理,那我就哭了

分配理論是jemalloc,可以理解為java版本的jemalloc實現。

PoolThreadCache

看完這篇還不清楚Netty的內存管理,那我就哭了

通過上圖可以清晰的了解到PoolThreadCache的主要數據結構。

開始的時候,這些Cache里面都是沒有值的,只有在調用free釋放的時候(在后續釋放內存中會講解),才會把之前分配的內存大小放到該cache的queue里面,其實每次分配的時候都是先看看是否緩存里面有,如果有直接返回,沒有則進行正常的分配流程(內存分配會講解)。

我們來看看PoolArena directArena內容:

看完這篇還不清楚Netty的內存管理,那我就哭了

下面我們來看看PoolArena結構。

PoolArena

看完這篇還不清楚Netty的內存管理,那我就哭了

通過下圖可以清晰的了解到PoolArena的主要數據結構。

看完這篇還不清楚Netty的內存管理,那我就哭了

在PoolArena里面涉及到PoolChunkList和PoolSubpage對應的結構有PoolChunk和PoolSubpage,我們來詳細的看看這2塊內容。

PoolChunk

第一次的時候,PoolChunkList、PoolSubpage都是默認值,需要新增一個Chunk,默認一個Chunk是16M。內部會結構是完全二叉樹一共有4096個節點,有2048個葉子節點(每個葉子節點大小為一個page,就是8k),非葉子節點的內存大小等于左子樹內存大小加上右子樹內存大小。

完全二叉樹結構如下:

看完這篇還不清楚Netty的內存管理,那我就哭了

這顆完全二叉樹在java中是使用數組來進行表示的。

唯一需要注意的是,下標是從1開始而不是0。

看完這篇還不清楚Netty的內存管理,那我就哭了

depthMap的值初始化后不再改變,memoryMap的值則隨著節點分配而改變。

看完這篇還不清楚Netty的內存管理,那我就哭了

這個值太多就不都截圖了,就是把上面那顆完全二叉樹用數組表示了而已,只是值存的不是節點的下標而是存的樹的深度而已。

depthMap數組值為0表示可以分配16M空間,如果為1 表示可以分配8M,,如果為2表示嗯可以分配4M,如果為3表示可以分配2M ……………………如果為11表示可以分配8k空間。

如果該節點已經分配完成,就設置為12即可。

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

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

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

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

知道深度之后,怎么進行定位到那個節點呢???

看完這篇還不清楚Netty的內存管理,那我就哭了

找到該節點之后,先把該節點顯示占用,在更新起父節點父節點的父………………如下:

看完這篇還不清楚Netty的內存管理,那我就哭了

SubpagePool

看完這篇還不清楚Netty的內存管理,那我就哭了

上面的圖就是關于SubpagePool的內存結構了。我們在分配page的時候,根據memoryMap對于的值就知道是否被分配了,那么如果是subpagePool呢?

subpagePool分為2類:tinySubpagePools和smallSubpagePools,大小對于也對于上面的圖里面了,每類都是固定大小的,如果分配256b的大小,那么一個page就是8k,8*1024/256 = 32塊。那么怎么怎么表示每個還被分配了呢?

  1. private final long[] bitmap; 

由于一個long占用的字節數為64,我們這里僅僅是需要表示32個,所以使用一個long即可了,二進制每位 1表示已經使用了,0表示還未使用。

看完這篇還不清楚Netty的內存管理,那我就哭了

由于subpage不僅僅需要定位到完全二叉樹在那個節點,還需要知道在long的第幾個 并且是第幾位,所以要復雜一些:

看完這篇還不清楚Netty的內存管理,那我就哭了

通過一個long的前32位來表示subpage的第幾個long的第幾位上面,通過后32來表示在完全二叉樹的那個節點上面,完美。

分配核心

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

進行跟進代碼:

看完這篇還不清楚Netty的內存管理,那我就哭了

我們來看:PooledByteBuf buf = newByteBuf(maxCapacity);

構建PooledByteBuf對象。最后返回PooledByteBuf對象。

我們來看下類繼承結構:

看完這篇還不清楚Netty的內存管理,那我就哭了

所有ByteBuf byteBuf = alloc.directBuffer(256);這句話是沒有什么問題的,不會報錯。

我們來看看newByteBuf(maxCapacity)的細節實現:

看完這篇還不清楚Netty的內存管理,那我就哭了

這里借助了Netty增加實現的Recycler對象池技術。Recycler設計也非常精巧,后續可以專門寫篇Recycler文章,今天不是重點,我們只要知道由于分配PolledByteBuf對象的代價有點大,如果需要頻繁使用到PolledByteBuf對象,并且對性能有所要求,那么池化技術是一個不錯的選擇(比如我們以前使用的線程池、數據庫連接池等都是類似道理),池化技術在一定程度上面減少了頻繁創建對象帶來的性能開銷。其實這個類似的思想非常常見(比如我們查詢數據庫成本高,緩存到redis,思路也是一樣的),在本篇后續中還可以體會到(PoolThreadCache)。

通過PooledByteBuf buf = newByteBuf(maxCapacity);僅僅是獲取到了一個初始對象而已。

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

看完這篇還不清楚Netty的內存管理,那我就哭了
  • 先嘗試在1步驟 進行分配,根據不同的類型定位到不同的Caches,如果有進行分配直接返回。
  • 如果1步驟 分配不了,進行2步驟上面分配。

2步驟分配細節:看看需要分配的是什么類型 page還是subpage,如果是subpage在根據看看是tinySubpagePools還是smallSubpagePools,找到對應的槽位,看看鏈表里是否有可用的PoolSubpage,如果有就進行分配修改標記退出,如果沒有就現需要在先分配一個page了,根據chunklist的這些看看是否有合適的,如果有合適的,那么在這些已經有的chunk上面進行分配一個page (分配page也是這個情況了)。

之后在根據分配到的page,進行該請求大小的分配 (由于一個page可以存儲很多同大小的數量)需要用long的位標記,表示該位置分配了,并且修改完全二叉樹的父等值,分配結束。如果沒有chunk那么需要新分配一塊chunk之后重復上面步驟即可。

釋放核心

釋放入口 :byteBuf.release();

進行跟進代碼:

看完這篇還不清楚Netty的內存管理,那我就哭了

 

看完這篇還不清楚Netty的內存管理,那我就哭了

 

看完這篇還不清楚Netty的內存管理,那我就哭了

通過這段代碼我們就這段放入到相應的queue了:

看完這篇還不清楚Netty的內存管理,那我就哭了

緩存到了對應的Cache的queue里面了。

責任編輯:華軒 來源: 匠心零度
相關推薦

2019-10-30 09:25:58

NginxApache 服務器

2023-07-13 09:05:57

react hook類型types

2023-08-07 11:07:30

5G電信TECS

2021-03-10 08:56:37

Zookeeper

2024-02-29 09:08:56

Encoding算法加密

2021-07-27 07:31:16

JavaArrayList數組

2022-05-15 21:52:04

typeTypeScriptinterface

2022-02-18 06:56:18

Wi-Fi路由器局域網

2018-05-22 16:24:20

HashMapJavaJDK

2018-12-17 12:30:05

Kubernetes存儲存儲卷

2020-10-30 08:20:04

SD卡TF卡存儲

2021-09-06 07:58:47

鏈表數據結構

2021-11-09 06:01:35

前端JITAOT

2020-09-10 16:10:17

js繼承模式前端

2022-07-29 12:29:09

CAS線程安全

2023-09-03 21:18:07

Python編程語言

2013-12-12 16:59:39

諾基亞微軟

2020-03-03 17:35:09

Full GCMinor

2023-02-27 15:46:19

數據元元數據

2019-06-25 15:00:53

SpringNullJava
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩国产精品一区二区三区 | 91av在线视频观看 | 成人午夜电影在线观看 | 国产精品伦理一区 | 中国一级特黄毛片大片 | av在线一区二区三区 | 2022精品国偷自产免费观看 | 爱爱免费视频网站 | 91精品国产综合久久久密闭 | 欧美一级片免费看 | 亚洲精品久久久久中文字幕二区 | 涩涩片影院 | 一区二区三区四区不卡 | 免费av一区二区三区 | 99久久久久国产精品免费 | 羞羞视频免费观看 | 亚洲综合色自拍一区 | 欧美一区不卡 | 亚洲一二三区不卡 | 亚洲区在线| 91精品国产综合久久香蕉922 | 欧美理伦片在线播放 | 性生生活大片免费看视频 | www.亚洲一区 | 亚州精品天堂中文字幕 | 国产成人一区 | 亚洲精品视频导航 | 亚洲欧美激情视频 | 日韩黄色小视频 | 国产精品视频一区二区三区不卡 | 久久久久久国产精品 | 亚洲精品日日夜夜 | 久久69精品久久久久久国产越南 | 精品久久一区 | 免费观看一级毛片视频 | 免费视频久久久久 | 亚洲精品久久久久久久不卡四虎 | 免费国产一区 | 亚洲一区二区三区视频 | 亚洲精品美女 | 欧美1级 |