精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

C++內存池優化:告別碎片化,提升性能

開發 前端
在內存池初始化時,一次性向操作系統申請blockSize * initialBlocks大小的內存,并將這些內存塊串聯成一個空閑鏈表,freeList指向鏈表的頭節點。

在C++編程的廣闊天地中,內存管理堪稱一道至關重要卻又布滿荊棘的關卡。當你精心雕琢代碼,滿心期待程序能如駿馬般奔騰馳騁時,內存問題卻常常像暗中使絆的 “小怪獸”,讓程序的性能大打折扣。你是否曾在程序運行過程中,眼睜睜看著內存占用如失控的氣球般不斷膨脹,運行速度卻越來越慢,最終陷入卡頓的泥沼?又是否在排查問題時,被復雜的內存錯誤信息折磨得焦頭爛額,卻始終找不到問題的根源?其實,這背后很大一部分原因,都與內存碎片化脫不了干系 。

傳統的 C++ 內存管理方式,如使用new和delete操作符,看似簡單直接,實則暗藏隱患。在程序頻繁地進行內存分配與釋放操作時,就如同在一塊原本平整的土地上隨意地挖坑、填坑,久而久之,土地變得坑洼不平,碎片化嚴重。這不僅導致內存空間的浪費,還使得后續的內存分配操作變得困難重重,就像在崎嶇的山路上尋找一塊合適的平地建房一樣,效率極低。而此時,內存池技術宛如一道曙光,照亮了 C++ 內存管理的困境,為我們提供了一種高效、優雅的解決方案 。

內存池,這個聽起來有些神秘的概念,究竟有著怎樣的魔力,能讓程序擺脫內存碎片化的束縛,實現性能的飛躍呢?接下來,就讓我們一同深入探索 C++ 內存池的奇妙世界,揭開它神秘的面紗,看看它是如何在內存管理的舞臺上大顯身手,讓我們的程序 “輕裝上陣”,飛速奔跑的 。

一、C++內存池簡介

內存池是一種內存分配方式,又被稱為固定大小區塊規劃(fixed-size-blocks allocation)。通常我們習慣直接使用new、malloc等API申請分配內存,這樣做的缺點在于:由于所申請內存塊的大小不定,當頻繁使用時會造成大量的內存碎片并進而降低性能。

在內核中有不少地方內存分配不允許失敗,作為一個在這些情況下確保分配的方式,內核開發者創建了一個已知為內存池(或者是 "mempool" )的抽象, 一個內存池真實地只是一類后備緩存,它盡力一直保持一個空閑內存列表給緊急時使用。

1.1為什么要用內存池?

C++程序默認的內存管理(new,delete,malloc,free)會頻繁地在堆上分配和釋放內存,導致性能的損失,產生大量的內存碎片,降低內存的利用率。默認的內存管理因為被設計的比較通用,所以在性能上并不能做到極致。因此,很多時候需要根據業務需求設計專用內存管理器,便于針對特定數據結構和使用場合的內存管理,比如:內存池。

(1)內存碎片問題

造成堆利用率很低的一個主要原因就是內存碎片化。如果有未使用的存儲器,但是這塊存儲器不能用來滿足分配的請求,這時候就會產生內存碎片化問題。內存碎片化分為內部碎片和外部碎片。

  • 內碎片:內部碎片是指一個已分配的塊比有效載荷大時發生的。(假設以前分配了10個大小的字節,現在只用了5個字節,則剩下的5個字節就會內碎片)。內部碎片的大小就是已經分配的塊的大小和他們的有效載荷之差的和。因此內部碎片取決于以前請求內存的模式和分配器實現(對齊的規則)的模式。
  • 外碎片:假設系統依次分配了16byte、8byte、16byte、4byte,還剩余8byte未分配。這時要分配一個24byte的空間,操作系統回收了一個上面的兩個16byte,總的剩余空間有40byte,但是卻不能分配出一個連續24byte的空間,這就是外碎片問題。

圖片圖片

(2)申請效率問題

例如:我們上學家里給生活費一樣,假設一學期的生活費是6000塊。

  • 方式1:開學時6000塊直接給你,自己保管,自己分配如何花。
  • 方式2:每次要花錢時,聯系父母,父母轉錢。

同樣是6000塊錢,第一種方式的效率肯定更高,因為第二種方式跟父母的溝通交互成本太高了。

同樣的道理,程序就像是上學的我們,操作系統就像父母,頻繁申請內存的場景下,每次需要內存,都像系統申請效率必然有影響。

1.2內存池原理

內存池的思想是,在真正使用內存之前,預先申請分配一定數量、大小預設的內存塊留作備用。當有新的內存需求時,就從內存池中分出一部分內存塊,若內存塊不夠再繼續申請新的內存,當內存釋放后就回歸到內存塊留作后續的復用,使得內存使用效率得到提升,一般也不會產生不可控制的內存碎片。

內存池設計算法原理:

  • 預申請一個內存區chunk,將內存中按照對象大小劃分成多個內存塊block
  • 維持一個空閑內存塊鏈表,通過指針相連,標記頭指針為第一個空閑塊
  • 每次新申請一個對象的空間,則將該內存塊從空閑鏈表中去除,更新空閑鏈表頭指針
  • 每次釋放一個對象的空間,則重新將該內存塊加到空閑鏈表頭
  • 如果一個內存區占滿了,則新開辟一個內存區,維持一個內存區的鏈表,同指針相連,頭指針指向最新的內存區,新的內存塊從該區內重新劃分和申請

通用內存分配和釋放的缺點如下:

  • 使用malloc/new申請分配堆內存時系統需要根據最先匹配、最優匹配或其它算法在內存空閑塊表中查找一塊空閑內存;使用free/delete釋放堆內存時,系統可能需要合并空閑內存塊,因此會產生額外開銷。
  • 頻繁使用時會產生大量內存碎片,從而降低程序運行效率。
  • 造成內存泄漏。

內存池(Memory Pool)是代替直接調用malloc/free、new/delete進行內存管理的常用方法,當申請內存空間時,會從內存池中查找合適的內存塊,而不是直接向操作系統申請。

內存池技術的優點如下:

  • 堆內存碎片很少。
  • 內存申請/釋放比malloc/new方式快。
  • 檢查任何一個指針是否在內存池中。
  • 寫一個堆轉儲(Heap-Dump)到硬盤。
  • 內存泄漏檢測(memory-leak detection),當沒有釋放分配的內存時,內存池(Memory Pool)會拋出一個斷言(assertion)。

內存池可以分為不定長內存池和定長內存池兩類。不定長內存池的典型實現包括Apache Portable Runtime中的apr_pool和GNU lib C中的obstack,而定長內存池的實現則有boost_pool等。對于不定長內存池,不需要為不同的數據類型創建不同的內存池,其缺點是無法將分配出的內存回收到池內;對于定長內存池,在使用完畢后,可以將內存歸還到內存池中,但需要為不同類型的數據結構創建不同的內存池,需要內存的時候要從相應的內存池中申請內存。

二、C++內存碎片與低效

在 C++ 的世界里,內存管理是一項至關重要卻又充滿挑戰的任務。當我們編寫 C++ 程序時,常常會用到new和delete(或者malloc和free )來進行動態內存的分配與釋放。例如,當我們需要創建一個對象或者數組時,會使用new來獲取所需的內存空間,當使用完畢后,再用delete將其釋放。

int* ptr = new int;
*ptr = 10;
// 使用ptr
delete ptr;

然而,這種看似簡單直接的內存管理方式,在面對頻繁的內存分配與釋放操作時,卻會暴露出諸多問題 ,其中最為突出的便是內存碎片和效率低下的問題。

2.1內存碎片問題

隨著程序的運行,如果不斷地進行小塊內存的分配與釋放,就會導致內存空間變得越來越零散。就好比我們有一個大書架(內存空間),一開始所有的書(數據)都整齊擺放,空間充足。但隨著不斷地借書(分配內存)和還書(釋放內存),書架上會出現許多零散的小空位(內存碎片),這些小空位無法被充分利用,即使后續有新的書要放(新的內存分配請求),也可能因為沒有足夠大的連續空位而無法放置,從而導致內存利用率降低。

這種內存碎片分為內部碎片和外部碎片。內部碎片是指分配的內存塊大于實際所需,多余的部分無法被利用;外部碎片則是由于頻繁的分配和釋放,使得空閑內存分散成許多小塊,無法滿足較大內存塊的分配需求。

2.2效率低下問題

每次使用new和delete進行內存操作時,都需要與操作系統進行交互,這涉及到系統調用等開銷,會消耗一定的時間。尤其是在需要頻繁分配和釋放內存的場景下,如游戲開發中大量創建和銷毀游戲對象,或者網絡編程中頻繁處理小數據包時,這種開銷會不斷累積,嚴重影響程序的運行效率。想象一下,你每次取一件工具都要跑到很遠的倉庫去取,用完再送回去,如此頻繁操作,工作效率必然低下。同樣,C++ 程序頻繁地向操作系統請求和歸還內存,也會使程序的執行效率大打折扣。

為了解決這些問題,內存池技術應運而生,它就像是一個高效的內存管家,能夠更加合理地管理內存,提升程序的性能和穩定性。

三、C++內存池技術詳解

3.1為什么要使用內存池

  • 解決內碎片問題
  • 由于向內存申請的內存塊都是比較大的,所以能夠降低外碎片問題
  • 一次性向內存申請一塊大的內存慢慢使用,避免了頻繁的向內存請求內存操作,提高內存分配的效率
  • 但是內碎片問題無法避免,只能盡可能的降低

3.2內存池的演變

最簡單的內存分配器,做一個鏈表指向空閑內存,分配就是取出一塊來,改寫鏈表,返回,釋放就是放回到鏈表里面,并做好歸并。注意做好標記和保護,避免二次釋放,還可以花點力氣在如何查找最適合大小的內存快的搜索上,減少內存碎片,有空你了還可以把鏈表換成伙伴算法。

  • 優點: 實現簡單
  • 缺點: 分配時搜索合適的內存塊效率低,釋放回歸內存后歸并消耗大,實際中不實用。

定長內存分配器,即實現一個 FreeList,每個 FreeList 用于分配固定大小的內存塊,比如用于分配 32字節對象的固定內存分配器,之類的。每個固定內存分配器里面有兩個鏈表,OpenList 用于存儲未分配的空閑對象,CloseList用于存儲已分配的內存對象,那么所謂的分配就是從 OpenList 中取出一個對象放到 CloseList 里并且返回給用戶,釋放又是從 CloseList 移回到 OpenList。分配時如果不夠,那么就需要增長 OpenList:申請一個大一點的內存塊,切割成比如 64 個相同大小的對象添加到 OpenList中。這個固定內存分配器回收的時候,統一把先前向系統申請的內存塊全部還給系統。

  • 優點: 簡單粗暴,分配和釋放的效率高,解決實際中特定場景下的問題有效。
  • 缺點: 功能單一,只能解決定長的內存需求,另外占著內存沒有釋放。

圖片圖片

哈希映射的FreeList池,在定長分配器的基礎上,按照不同對象大小(8,16,32,64,128,256,512,1k…64K),構造十多個固定內存分配器,分配內存時根據要申請內存大小進行對齊然后查H表,決定到底由哪個分配器負責,分配后要在內存頭部的 header 處寫上 cookie,表示由該塊內存哪一個分配器分配的,這樣釋放時候你才能正確歸還。如果大于64K,則直接用系統的 malloc作為分配,如此以浪費內存為代價你得到了一個分配時間近似O(1)的內存分配器。這種內存池的缺點是假設某個 FreeList 如果高峰期占用了大量內存即使后面不用,也無法支援到其他內存不夠的 FreeList,達不到分配均衡的效果。

  • 優點:這個本質是定長內存池的改進,分配和釋放的效率高。可以解決一定長度內的問題。
  • 缺點:存在內碎片的問題,且將一塊大內存切小以后,申請大內存無法使用。多線程并發場景下,鎖競爭激烈,效率降低。

范例:sgi stl 六大組件中的空間配置器就是這種設計實現的。

圖片圖片

了解malloc底層原理

C 標準庫函數malloc 在底層使用的是 —– 分離適配,使用這種方法,分配器維護著一個空閑鏈表數組,每個空閑鏈表被組織成某種類型的顯示/隱式鏈表。每個鏈表包含大小不同的塊,這些塊的大小是大小類的成員,當要分配一個塊時,我們確定了大小類之后,對適當的空閑鏈表做首次適配,查找一個合適的塊,如果找到,那么可選地分割它,并將剩余的部分插入到適當的空閑鏈表中。如果每找到,那就搜索下一個更大的大小類的空閑鏈表,重復直到找到一個合適的塊。如果空閑鏈表中沒有合適的塊,那么就向操作系統請求額外的堆存儲器,從這個新的堆存儲器中分配一個塊,將剩余部分放置在適當的大小類中,當釋放一個塊時,我們執行合并,并將結果放在相應的空閑鏈表中。

  • malloc優點: 使用自由鏈表的數組,提高分配釋放效率;減少內存碎片,可以合并空閑的內存
  • malloc缺點:為了維護隱式/顯示鏈表需要維護一些信息,空間利用率不高;在多線程的情況下,會出現線程安全的問題,如果以加鎖的方式解決,會大大降低效率。

3.3內存池的核心原理

內存池的工作原理基于一種預先分配和重復利用的策略。在程序啟動階段,內存池會一次性向操作系統申請一塊較大的連續內存空間,這就好比我們提前租下了一整棟大樓(大塊內存)。隨后,內存池會將這塊大內存按照一定的規則劃分為多個較小的內存塊,這些小內存塊就像是大樓里的一個個房間。

為了有效管理這些內存塊,內存池通常會借助一些數據結構,其中鏈表和哈希表是較為常用的。以鏈表為例,所有空閑的內存塊會通過指針相互連接,形成一個空閑內存塊鏈表。當程序有內存分配請求時,內存池就會從這個鏈表中取出一個合適的內存塊分配給程序,就像從空閑房間列表中挑選一間租出去 。當程序使用完內存并釋放時,該內存塊又會被重新插入到空閑鏈表中,等待下一次分配,如同租客退房后房間又可供新租客租用。

而哈希表則可以更快速地定位到合適大小的內存塊。通過將內存塊的大小或其他特征作為鍵值,哈希表能夠在近乎常數的時間內找到滿足需求的內存塊,大大提高了內存分配的效率,尤其適用于需要頻繁分配不同大小內存塊的場景。

3.4內存池的顯著優勢

  • 減少內存碎片:內存池通過預先分配大塊內存,并在內部進行小塊內存的管理,避免了頻繁向操作系統申請和釋放小塊內存所導致的內存碎片問題。因為內存池內的內存分配和釋放都在預先分配的大塊內存范圍內進行,就像在一個獨立的小區內分配房屋,不會影響到小區外的空間布局,從而保持了內存空間的連續性和規整性,提高了內存利用率。
  • 提升分配釋放效率:由于內存池的內存分配和釋放操作是在用戶態進行的,無需頻繁與操作系統內核進行交互,避免了系統調用的開銷。就像在自家倉庫取放物品,無需每次都向管理員申請,節省了溝通成本和時間。而且內存池可以采用更高效的數據結構和算法來管理內存塊,使得分配和釋放操作更加快速,能夠顯著提升程序在頻繁內存操作場景下的運行效率。
  • 降低內存泄漏風險:內存池可以設計成具有自動回收機制。當程序中某些內存塊被遺忘釋放時,內存池能夠在適當的時候將這些內存塊回收,重新納入可分配的內存池中,從而降低了內存泄漏的可能性。例如,當一個對象從內存池中分配內存后,在其生命周期結束時,內存池可以自動檢測并回收該對象占用的內存,無需程序員手動釋放,減少了因人為疏忽導致的內存泄漏問題。

四、C++內存池實現方案

4.1設計問題

我們在設計內存池的實現方案時,需要考慮到以下問題:

①內存池是否可以自動增長?

如果內存池的最大空間是固定的(也就是非自動增長),那么當內存池中的內存被請求完之后,程序就無法再次從內存池請求到內存。所以需要根據程序對內存的實際使用情況來確定是否需要自動增長。

②內存池的總內存占用是否只增不減?

如果內存池是自動增長的,就涉及到了“內存池的總內存占用是否是只增不減”這個問題了。試想,程序從一個自動增長的內存池中請求了1000個大小為100KB的內存片,并在使用完之后全部歸還給了內存池,而且假設程序之后的邏輯最多之后請求10個100KB的內存片,那么該內存池中的900個100KB的內存片就一直處于閑置狀態,程序的內存占用就一直不會降下來。對內存占用大小有要求的程序需要考慮到這一點。

③內存池中內存片的大小是否固定?

如果每次從內存池中的請求的內存片的大小如果不固定,那么內存池中的每個可用內存片的大小就不一致,程序再次請求內存片的時候,內存池就需要在“匹配最佳大小的內存片”和“匹配操作時間”上作出衡量。“最佳大小的內存片”雖然可以減少內存的浪費,但可能會導致“匹配時間”變長。

④內存池是否是線程安全的?

是否允許在多個線程中同時從同一個內存池中請求和歸還內存片?這個線程安全可以由內存池來實現,也可以由使用者來保證。

⑤內存片分配出去之前和歸還到內存池之后,其中的內容是否需要被清除?

程序可能出現將內存片歸還給內存池之后,仍然使用內存片的地址指針進行內存讀寫操作,這樣就會導致不可預期的結果。將內容清零只能盡量的(也不一定能)將問題拋出來,但并不能解決任何問題,而且將內容清零會消耗一定的CPU時間。所以,最終最好還是需要由內存池的使用者來保證這種安全性。

⑥是否兼容std::allocator?

STL標準庫中的大多類都支持用戶提供一個自定義的內存分配器,默認使用的是std::allocator,如std::string:

typedef basic_string<char, char_traits<char>, allocator<char> > string;

如果我們的內存池兼容std::allocator,那么我們就可以使用我們自己的內存池來替換默認的std::allocator分配器,如:

typedef basic_string<char, char_traits<char>, MemoryPoll<char> > mystring

2.2常見內存池實現方案

(1)固定大小緩沖池

固定大小緩沖池適用于頻繁分配和釋放固定大小對象的情況。

(2)dlmalloc

dlmalloc 是一個內存分配器,由Doug Lea從1987年開始編寫,目前最新版本為2.8.3,由于其高效率等特點被廣泛使用和研究。

(3) SGI STL內存分配器

SGI STL allocator 是目前設計最優秀的 C++ 內存分配器之一,其內部free_list[16] 數組負責管理從 8 bytes到128 bytes不同大小的內存塊( chunk ),每一個內存塊都由連續的固定大小( fixed size block )的很多 chunk 組成,并用指針鏈表連接。

(4)Loki小對象分配器

Loki 分配器使用vector管理數組,可以指定 fixed size block 的大小。free blocks分布在一個連續的大內存塊中,free chunks 可以根據使用情況自動增長和減少合適的數目,避免內存分配得過多或者過少。

(5)Boost object_pool

Boost object_pool 可以根據用戶具體應用類的大小來分配內存塊,通過維護一個free nodes的鏈表來管理。可以自動增加nodes塊,初始32個nodes,每次增加都以兩倍數向system heap要內存塊。object_pool 管理的內存塊需要在其對象銷毀的時候才返還給 system heap 。

(6)ACE_Cached_Allocator 和 ACE_Free_List

ACE 框架中包含一個可以維護固定大小的內存塊的分配器,通過在 ACE_Cached_Allocator 中定義Free_list 鏈表來管理一個連續的大內存塊,內存塊中包含多個固定大小的未使用內存區塊( free chunk),同時使用ACE_unbounded_Set維護已使用的chuncks 。

(7)TCMalloc

Google開源項目gperftools提供了內存池實現方案。TCMalloc替換了系統的malloc,更加底層優化,性能更好。

4.3STL內存分配器

分配器(allocator))是C ++標準庫的一個組件, 主要用來處理所有給定容器(vector,list,map等)內存的分配和釋放。C ++標準庫提供了默認使用的通用分配器std::allocator,但開發者可以自定義分配器。

GNU STL除了提供默認分配器,還提供了__pool_alloc、__mt_alloc、array_allocator、malloc_allocator 內存分配器。

  • __pool_alloc :SGI內存池分配器
  • __mt_alloc :多線程內存池分配器
  • array_allocator :全局內存分配,只分配不釋放,交給系統來釋放
  • malloc_allocator :堆std::malloc和std::free進行的封裝

五、C++內存池的具體實現

5.1內存池的多樣類型

在C++編程中,內存池根據其分配內存塊的方式和特點,可以分為不同的類型每種類型都有其獨特的適用場景 。了解這些類型和場景,能夠幫助我們更精準地選擇和使用內存池,優化程序性能。

(1)固定內存池

固定內存池,正如其名,每次從內存池中分配出來的內存單元大小是固定不變的。在程序初始化時,就預先設定好內存塊的大小。例如,我們創建一個用于管理小型數據結構(如鏈表節點)的固定內存池,每個內存塊大小設為 32 字節。當程序需要創建鏈表節點時,直接從這個內存池中獲取 32 字節的內存塊,無需再向操作系統申請。

固定內存池的優點十分顯著。由于內存塊大小固定,其分配和釋放操作非常高效,就像在一個裝滿同樣大小盒子的倉庫里取放物品,無需挑選和測量,直接拿取或放回即可。而且,因為內存塊大小一致,在分配和回收過程中不會產生不同大小的內存空洞,能夠有效減少內存碎片,提高內存利用率。在游戲開發中,大量的游戲對象(如子彈、怪物等)具有相同的大小和結構,使用固定內存池來管理這些對象的內存分配,可以顯著提升游戲的性能和穩定性。

(2)可變內存池

可變內存池則具有更高的靈活性,它能夠根據實際需求分配不同大小的內存塊。當程序需要分配 10 字節的內存用于存儲小型數據,又需要分配 100 字節的內存用于存儲較大的數據結構時,可變內存池都能滿足這些不同的需求。

可變內存池適用于內存需求變化較大的場景。在網絡編程中,網絡數據包的大小是不確定的,可能是幾十字節的小數據包,也可能是數千字節的大數據包,此時可變內存池就能很好地適應這種變化,為不同大小的數據包分配合適的內存空間。然而,可變內存池的實現相對復雜,因為它需要管理不同大小的內存塊,在分配和釋放內存時需要進行更復雜的算法操作,以確保內存的高效利用和避免內存碎片,就像在一個裝滿各種不同大小物品的倉庫里找東西,需要花費更多的時間和精力去尋找和整理。

5.2案例實現分析

(1)案例分析

計劃實現一個內存池管理的類MemoryPool,它具有如下特性:

  • 內存池的總大小自動增長。
  • 內存池中內存片的大小固定。
  • 支持線程安全。
  • 在內存片被歸還之后,清除其中的內容。
  • 兼容std::allocator。

因為內存池的內存片的大小是固定的,不涉及到需要匹配最合適大小的內存片,由于會頻繁的進行插入、移除的操作,但查找比較少,故選用鏈表數據結構來管理內存池中的內存片。

MemoryPool中有2個鏈表,它們都是雙向鏈表(設計成雙向鏈表主要是為了在移除指定元素時,能夠快速定位該元素的前后元素,從而在該元素被移除后,將其前后元素連接起來,保證鏈表的完整性):

  • data_element_ 記錄以及分配出去的內存片。
  • free_element_ 記錄未被分配出去的內存片。

①內存塊結構體(Block Structure):內存塊結構體是內存池管理的基本單元,它用來表示內存池中每一個可分配的內存塊。

struct MemoryBlock {
    MemoryBlock* next; // 指向下一個內存塊的指針,用于構建鏈表
    // 可以在這里添加其他元數據,如內存塊的大小標識等
};

在這個結構體中,next指針起著至關重要的作用,它將各個內存塊串聯起來,形成一個鏈表結構。通過這個鏈表,內存池可以方便地管理空閑內存塊和已分配內存塊 。比如,在空閑內存塊鏈表中,每個節點都是一個MemoryBlock結構體,通過next指針可以快速找到下一個空閑塊,當有內存分配請求時,就能迅速從鏈表中取出一個空閑塊進行分配。

空閑內存塊鏈表(Free List):空閑內存塊鏈表是內存池管理空閑內存的核心數據結構。它是由MemoryBlock結構體組成的鏈表,鏈表中的每一個節點都代表一個可用的空閑內存塊。

class MemoryPool {
private:
    MemoryBlock* freeList; // 空閑內存塊鏈表的頭指針
    // 其他成員變量和函數...
};

freeList作為鏈表的頭指針,指向鏈表中的第一個空閑內存塊。當內存池初始化時,會將預先分配的內存塊逐一加入到這個鏈表中,使它們成為可用的空閑資源。在內存分配過程中,內存池會從freeList所指向的鏈表頭部取出一個內存塊分配給用戶,然后更新freeList指針,使其指向下一個空閑塊;而在內存釋放時,被釋放的內存塊會被重新插入到鏈表頭部,成為新的空閑塊,方便下次分配使用。

(2)分配與釋放流程

①內存分配流程:當程序向內存池請求分配內存時,內存池首先會檢查空閑內存塊鏈表freeList是否為空。如果鏈表不為空,說明有可用的空閑內存塊,內存池會直接從鏈表頭部取出一個內存塊返回給程序,同時更新freeList指針,使其指向下一個空閑塊。這一過程就像從貨架上取走一件商品,然后調整貨架的指示標識。

void* MemoryPool::allocate() {
    if (freeList == nullptr) {
        expandPool(); // 內存不足,擴展內存池
    }
    MemoryBlock* block = freeList;
    freeList = freeList->next;
    return block;
}

如果freeList為空,意味著當前內存池中沒有空閑內存塊可供分配,這時內存池就需要擴展自身的內存空間。擴展內存池的方式通常是向操作系統申請一塊新的更大的內存區域,然后將這塊新內存按照內存塊的大小進行劃分,并將新劃分出的內存塊加入到空閑內存塊鏈表中,以供后續分配使用 。

內存釋放流程:當程序使用完內存并將其釋放回內存池時,內存池會將釋放的內存塊重新插入到空閑內存塊鏈表freeList的頭部。這樣,該內存塊就又成為了可用的空閑資源,等待下一次被分配使用。

void MemoryPool::deallocate(void* ptr) {
    MemoryBlock* block = static_cast<MemoryBlock*>(ptr);
    block->next = freeList;
    freeList = block;
}

這個過程就像是將歸還的商品重新擺放在貨架的顯眼位置,方便下次快速取用。通過這種方式,內存池實現了內存的循環利用,大大提高了內存的使用效率。

(3)線程安全機制

在多線程環境下,內存池面臨著數據競爭和不一致的問題。多個線程同時訪問和操作內存池時,可能會出現一個線程在讀取空閑內存塊鏈表時,另一個線程對鏈表進行了修改,導致讀取的數據不準確,或者出現內存塊被重復分配、釋放等錯誤情況。

為了解決這些問題,常見的實現線程安全的方法有以下幾種:

①互斥鎖(Mutex):互斥鎖是一種常用的同步機制,它可以保證在同一時刻只有一個線程能夠訪問內存池的關鍵數據結構和操作。在 C++ 中,可以使用std::mutex來實現互斥鎖。

class MemoryPool {
private:
    std::mutex mtx;
    MemoryBlock* freeList;
public:
    void* allocate() {
        std::lock_guard<std::mutex> lock(mtx);
        // 分配內存的邏輯
    }
    void deallocate(void* ptr) {
        std::lock_guard<std::mutex> lock(mtx);
        // 釋放內存的邏輯
    }
};

在allocate和deallocate函數中,通過std::lock_guard<std::mutex> lock(mtx);語句創建了一個鎖對象,它會在構造時自動鎖定互斥鎖mtx,在析構時自動解鎖,從而確保了在這兩個函數執行期間,其他線程無法同時訪問內存池,避免了數據競爭。

無鎖數據結構(Lock - Free Data Structures):無鎖數據結構利用原子操作和特殊的算法來實現多線程安全,避免了鎖帶來的開銷。例如,使用std::atomic類型來實現無鎖鏈表。通過std::atomic的原子操作,可以保證對鏈表指針的修改是原子的,不會被其他線程打斷,從而實現了多線程環境下的安全操作。但無鎖數據結構的實現較為復雜,需要對原子操作和并發編程有深入的理解 。

(4)實戰演練:代碼示例

為了更直觀地理解 C++ 內存池的實現,下面我們來看一個簡單的固定內存池的代碼示例。這個內存池專門用于分配固定大小的內存塊,通過鏈表來管理空閑內存塊 。

#include <iostream>
#include <cstdlib>
#include <cassert>

// 定義內存塊結構體
struct MemoryBlock {
    MemoryBlock* next; // 指向下一個內存塊的指針
};

class MemoryPool {
public:
    MemoryPool(size_t blockSize, size_t initialBlocks)
        : blockSize(blockSize), initialBlocks(initialBlocks) {
        // 初始化內存池
        initializePool();
    }

    ~MemoryPool() {
        // 釋放內存池中的所有內存
        MemoryBlock* current = poolStart;
        while (current) {
            MemoryBlock* next = current->next;
            free(current);
            current = next;
        }
    }

    void* allocate() {
        if (!freeList) {
            // 空閑鏈表為空,擴展內存池
            expandPool();
        }
        MemoryBlock* block = freeList;
        freeList = freeList->next;
        return block;
    }

    void deallocate(void* ptr) {
        MemoryBlock* block = static_cast<MemoryBlock*>(ptr);
        block->next = freeList;
        freeList = block;
    }

private:
    void initializePool() {
        // 申請初始內存塊并構建空閑鏈表
        poolStart = static_cast<MemoryBlock*>(malloc(blockSize * initialBlocks));
        assert(poolStart != nullptr);

        freeList = poolStart;
        MemoryBlock* current = poolStart;
        for (size_t i = 1; i < initialBlocks; ++i) {
            current->next = static_cast<MemoryBlock*>(reinterpret_cast<char*>(current) + blockSize);
            current = current->next;
        }
        current->next = nullptr;
    }

    void expandPool() {
        // 擴展內存池,每次新增10個內存塊
        size_t newBlocks = 10;
        MemoryBlock* newBlock = static_cast<MemoryBlock*>(malloc(blockSize * newBlocks));
        assert(newBlock != nullptr);

        MemoryBlock* current = newBlock;
        for (size_t i = 1; i < newBlocks; ++i) {
            current->next = static_cast<MemoryBlock*>(reinterpret_cast<char*>(current) + blockSize);
            current = current->next;
        }
        current->next = freeList;
        freeList = newBlock;
    }

    size_t blockSize; // 每個內存塊的大小
    size_t initialBlocks; // 初始內存塊數量
    MemoryBlock* poolStart; // 內存池起始地址
    MemoryBlock* freeList; // 空閑內存塊鏈表頭指針
};

// 示例使用
int main() {
    MemoryPool pool(16, 5); // 每個內存塊16字節,初始5個內存塊

    void* ptr1 = pool.allocate();
    void* ptr2 = pool.allocate();

    pool.deallocate(ptr1);
    pool.deallocate(ptr2);

    return 0;
}

MemoryBlock 結構體:定義了內存塊的結構,包含一個指向下一個內存塊的指針next,用于構建鏈表。

MemoryPool 類:內存池的核心類,包含以下成員:

構造函數:MemoryPool(size_t blockSize, size_t initialBlocks),接收每個內存塊的大小blockSize和初始內存塊數量initialBlocks,并調用initializePool初始化內存池。析構函數:~MemoryPool(),釋放內存池中所有申請的內存。allocate函數:從空閑鏈表中取出一個內存塊分配給用戶。如果空閑鏈表為空,則調用expandPool擴展內存池。deallocate函數:將用戶釋放的內存塊重新插入到空閑鏈表的頭部。

  • initializePool 函數:在內存池初始化時,一次性向操作系統申請blockSize * initialBlocks大小的內存,并將這些內存塊串聯成一個空閑鏈表,freeList指向鏈表的頭節點。
  • expandPool 函數:當空閑鏈表為空時,調用此函數擴展內存池。每次擴展新增 10 個內存塊,將新申請的內存塊加入到空閑鏈表的頭部。
  • main 函數:演示了內存池的基本使用,先分配兩個內存塊,然后釋放它們 。

通過這個示例,我們可以看到內存池如何通過預先分配內存和管理空閑鏈表,實現高效的內存分配與釋放,減少內存碎片和系統調用開銷 。

責任編輯:武曉燕 來源: 深度Linux
相關推薦

2025-04-22 03:00:00

2023-09-26 12:02:34

C++循環

2024-12-31 00:00:15

2025-10-17 09:18:16

2021-06-10 09:40:12

C++性能優化Linux

2025-08-01 01:55:00

2025-08-05 09:24:30

2025-07-01 02:25:00

2013-09-11 16:11:57

C++StringBuild

2017-01-10 14:08:33

C++StringBuild性能

2024-05-06 11:19:20

內存池計算機編程

2025-05-09 03:55:00

2024-03-05 09:55:00

C++右值引用開發

2024-12-27 09:21:58

2024-01-31 23:51:22

C++移動語義代碼

2024-06-13 08:24:43

SpringGateway線程池

2025-03-28 08:35:00

2023-10-12 19:41:55

2024-01-25 16:19:27

2024-11-05 16:29:57

點贊
收藏

51CTO技術棧公眾號

欧美天堂一区二区三区| 国产午夜亚洲精品午夜鲁丝片| 久久亚洲精品中文字幕冲田杏梨 | 日韩不卡av在线| 亚洲日本中文| 亚洲va欧美va国产va天堂影院| 久久草.com| 91片黄在线观看喷潮| 一本色道久久综合亚洲精品高清| 国产一区二区动漫| 欧美成人精品一区二区综合免费| 天天免费亚洲黑人免费| 亚洲乱码国产乱码精品精可以看| 精品日韩电影| 国产成人精品一区二三区四区五区| 亚洲欧美日韩国产| 久久国产精品视频| 天天干天天舔天天操| 超碰在线亚洲| 91精品中文字幕一区二区三区| 少妇高潮喷水久久久久久久久久| 国产在线观看免费麻豆| 久久久综合精品| 99re国产视频| 亚洲性生活大片| 久久人人97超碰国产公开结果| 欧美人与物videos| 亚洲综合图片一区| 欧洲乱码伦视频免费| 亚洲第一国产精品| 亚洲丝袜在线观看| 欧美日韩卡一| 欧美亚洲国产bt| 91传媒久久久| 男人天堂视频在线观看| 亚洲图片自拍偷拍| www.日本三级| a级网站在线播放| 中文字幕 久热精品 视频在线 | 一区二区三区日韩在线观看| 亚洲国产一区二区三区在线| 欧美日韩伦理片| 91污片在线观看| 久久av免费观看| 天天干,夜夜操| 成人爱爱电影网址| 国产欧美日韩综合一区在线观看| 亚洲a视频在线观看| 国产精品影视网| 亚洲在线观看视频| av天堂一区二区三区| 国产成人在线影院| 99porn视频在线| 日本免费不卡视频| 97久久精品人人做人人爽50路| 国产手机精品在线| 亚洲欧美日韩综合在线| 91蜜桃婷婷狠狠久久综合9色| 精品亚洲一区二区三区四区五区高| 欧日韩在线视频| 99久久er热在这里只有精品15| 国产伦精品一区二区三区高清版| 天天干,夜夜爽| 972aa.com艺术欧美| 欧美国产一区二区在线| 黄色小视频在线观看| 国产欧美日韩视频在线观看| 欧美日韩国产精品一卡| 成人免费高清在线播放| 国产精品福利av| 肉大捧一出免费观看网站在线播放| 黄色免费在线观看网站| 一区二区三区四区国产精品| 可以看毛片的网址| 亚洲国产福利| 欧美高清dvd| 精人妻一区二区三区| 天海翼亚洲一区二区三区| 亚洲码在线观看| 美女福利视频网| 国产精品av久久久久久麻豆网| 性欧美视频videos6一9| 波多野结衣大片| 国内精品在线播放| 久久伦理网站| 巨大荫蒂视频欧美另类大| 亚洲五码中文字幕| 熟女人妇 成熟妇女系列视频| 欧美成人毛片| 亚洲白虎美女被爆操| 波多野结衣av在线观看| 在线精品国产| 欧美孕妇与黑人孕交| 一区精品在线观看| 成人黄色在线视频| 午夜一区二区三视频在线观看| www.久久久久.com| 色综合色狠狠天天综合色| 在线播放av中文字幕| 日韩欧美影院| 欧美成人黑人xx视频免费观看| 久久午夜免费视频| 国内成人自拍视频| 欧美精品一区在线发布| 国产区在线观看| 色欲综合视频天天天| 潘金莲一级淫片aaaaaaa| 精品黄色一级片| 韩国国内大量揄拍精品视频| 伊人久久亚洲综合| 99精品视频在线免费观看| 日本xxx免费| 性欧美videohd高精| 精品免费国产一区二区三区四区| a资源在线观看| 一本久久综合| av一区二区三区四区电影| 成人动漫在线免费观看| 精品日本美女福利在线观看| 亚洲成人av免费观看| av资源久久| 青草青草久热精品视频在线网站 | 中文字幕视频在线免费欧美日韩综合在线看 | 中文字幕一区二区三| 成人在线激情网| 久久a级毛片毛片免费观看| 久久中文字幕在线| 伊人成人在线观看| 欧美激情一区二区三区四区| 欧美极品欧美精品欧美图片| 国产三级精品三级在线观看国产| 久久av在线看| 国产裸体永久免费无遮挡| 中文字幕二三区不卡| 男人天堂成人在线| 夜夜春成人影院| 欧美亚洲国产日本| 日本电影一区二区在线观看| 亚洲成年人网站在线观看| 人妻互换一二三区激情视频| 欧美精品国产一区二区| 亚洲综合最新在线| a毛片在线播放| 日韩你懂的在线播放| 欧美日韩在线国产| 国产iv一区二区三区| 久久www视频| 伊人久久大香线蕉av超碰| 欧美日韩国产999| а√中文在线资源库| 亚洲在线成人精品| 91传媒理伦片在线观看| 亚洲国产专区| 久久青青草原一区二区| 日韩av福利| 色诱女教师一区二区三区| 亚洲一区二区三区高清视频| 国产精品青草综合久久久久99| 91色国产在线| 色婷婷一区二区三区| 91免费视频网站| 在线看福利影| 亚洲精品大尺度| 久久青青草原亚洲av无码麻豆| 久久久久久久久久久电影| 能看的毛片网站| 四虎成人av| 亚洲一区二区三区成人在线视频精品| 在线免费av导航| 日韩av在线电影网| 国产一级片免费视频| 国产精品久久久久一区| 国产chinesehd精品露脸| 夜夜嗨av一区二区三区网站四季av| 鲁丝一区鲁丝二区鲁丝三区| 91亚洲视频| 欧美人与性动交a欧美精品| 亚洲色图狠狠干| 欧美日韩激情在线| 精品人妻在线播放| 国产午夜精品美女毛片视频| 日韩av最新在线观看| 欧美日韩综合网| 国产精品成人国产| 久久在线免费视频| 日韩在线一区二区三区四区| 欧美性猛交xxxx免费看漫画| av电影在线不卡| 国产米奇在线777精品观看| 成人性生活视频免费看| 欧洲乱码伦视频免费| 97在线中文字幕| av有声小说一区二区三区| 日韩在线观看高清| 亚洲av成人精品毛片| 666欧美在线视频| 日韩毛片在线播放| 国产精品传媒视频| 在线观看av中文字幕| 久久99精品国产.久久久久久| 免费看毛片的网址| 久久免费av| 久久精品ww人人做人人爽| av日韩一区| 秋霞午夜一区二区| 色呦呦在线视频| 伊人男人综合视频网| 人妻中文字幕一区| 7777精品伊人久久久大香线蕉| 日韩黄色一级大片| 亚洲欧美另类小说视频| 国产精品一二三区在线观看| 成人美女视频在线观看18| 成人性生交免费看| 久久久夜精品| 欧美 日韩 激情| 国产综合色产| 日韩视频一二三| 四虎成人精品永久免费av九九| 久久久久国产精品视频| 中文字幕日韩高清在线| 国产精品三级久久久久久电影| 国产精品一二三产区| 欧美激情第1页| av软件在线观看| 亚洲丝袜在线视频| 能在线看的av| 国产视频一区在线| 无码精品人妻一区二区三区影院| 欧美一区二区免费观在线| 在线免费a视频| 欧美优质美女网站| 国产无遮挡又黄又爽又色视频| 天天亚洲美女在线视频| 国产无遮挡裸体免费视频| 亚洲一区二区五区| 麻豆视频在线观看| 一区二区在线观看免费| a在线视频播放观看免费观看| 国产精品乱码久久久久久| 久久国产柳州莫菁门| 久久精品欧美一区二区三区麻豆| 泷泽萝拉在线播放| 久久女同精品一区二区| 色婷婷在线影院| 久久久久88色偷偷免费| 日本精品在线观看视频| 亚洲国产精品传媒在线观看| 欧洲美熟女乱又伦| 欧美激情在线观看视频免费| 懂色av蜜桃av| 日韩毛片高清在线播放| 国产一二三av| 亚洲欧美偷拍卡通变态| 久草网在线观看| 亚洲高清免费观看高清完整版在线观看| 欧美久久久久久久久久久久| 一区二区三区美女视频| 久久精品国产亚洲av麻豆色欲| 图片区小说区国产精品视频| 国产一级精品视频| 91成人国产精品| 国产一区二区麻豆| 日韩亚洲欧美在线| 午夜小视频免费| 国产一区二区三区在线免费观看| 97电影在线看视频| 美日韩精品免费视频| xxxx在线视频| 国产97色在线| 成年永久一区二区三区免费视频 | 中日韩黄色大片| 欧美系列一区二区| www日本高清| 亚洲毛片在线观看| 黄色片网站在线| 午夜精品久久久久久久久久久久久| www.com.cn成人| 成人黄色生活片| 粉嫩精品导航导航| 日韩福利在线| 欧美日韩日本国产亚洲在线 | 日韩大陆欧美高清视频区| 国产资源在线看| 欧美成年人视频网站| 中文字幕人成乱码在线观看| 国产乱人伦真实精品视频| 一区二区网站| 日韩国产高清一区| 国产真实久久| 五月婷婷丁香色| 99热99精品| www.毛片com| 色婷婷综合在线| 性一交一乱一色一视频麻豆| 亚洲色图35p| 激情在线视频播放| 国产精品视频一区国模私拍 | 国产在线视频一区二区三区| 污污内射在线观看一区二区少妇| 国产精品三级视频| 天海翼一区二区| 欧美丰满少妇xxxxx高潮对白| 亚洲人视频在线观看| 欧美丰满少妇xxxxx做受| 欧洲成人一区| 蜜桃视频在线观看成人| 欧美在线黄色| 四季av一区二区| 26uuu精品一区二区| 欧美成人精品欧美一级| 欧美三级电影在线观看| 亚洲欧美日韩成人在线| 久久久久久久久久国产精品| 日韩电影精品| 五月婷婷综合色| 美女网站久久| 一级性生活大片| 午夜精品久久久久影视| 国产成人精品一区二区无码呦| 深夜福利国产精品| 国偷自产一区二区免费视频| 国产三区二区一区久久| 欧美日韩视频一区二区三区| 手机在线免费毛片| 中文字幕一区二区在线观看| 中文字幕精品在线观看| 亚洲视频在线播放| 中国色在线日|韩| 国外成人免费视频| 精品99视频| 成人在线电影网站| 亚洲一卡二卡三卡四卡五卡| 国产高清视频免费| 欧美大成色www永久网站婷| 国产亚洲高清一区| av磁力番号网| 国产另类ts人妖一区二区| 青青操在线视频观看| 欧美日韩黄视频| 免费在线看黄| 成人免费激情视频| 在线看片不卡| 在线精品视频播放| 亚洲18女电影在线观看| 色综合久久久久久| 26uuu久久噜噜噜噜| 色先锋久久影院av| 国产自偷自偷免费一区| 国产欧美一区二区精品仙草咪| 国产在线一级片| 中文字幕国产日韩| 国产一区二区三区视频在线 | 在线综合欧美| 91精彩刺激对白露脸偷拍| 在线一区二区三区| 在线播放日本| 91九色在线免费视频| 亚洲激情视频| 高潮毛片无遮挡| 欧美日韩国产系列| free性欧美hd另类精品| 国产精品国产三级国产专区53 | 婷婷开心久久网| 日本ー区在线视频| 国产精品久久久久久久久借妻| 久久视频国产| 精品伦一区二区三区| 富二代精品短视频| 婷婷在线视频观看| 懂色av一区二区三区在线播放| 一本色道久久综合亚洲精品不| 久久久久久久久久久久久久久| 欧美日韩国产经典色站一区二区三区 | 久久亚洲精品石原莉奈| xxxx性欧美| 国产日韩三级| 国产九九在线观看| 亚洲午夜久久久久久久久电影网 | 亚洲成人中文字幕在线| 2019精品视频| 97色伦图片97综合影院| 香蕉在线观看视频| 一本色道久久综合狠狠躁的推荐| 色综合久久影院| 国产视频精品网| 麻豆国产91在线播放| 国产在线视频99| 中文字幕一区日韩电影| 风间由美性色一区二区三区四区 | 人人鲁人人莫人人爱精品| 少妇高潮流白浆| 2020日本不卡一区二区视频| 亚洲综合精品在线| 2019中文字幕免费视频| 午夜国产一区二区| xxxx日本免费| 日韩视频国产视频| 123成人网| 日韩欧美一区二|