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

告別內(nèi)存分配煩惱,定長(zhǎng)內(nèi)存池來“救場(chǎng)”

開發(fā) 前端
當(dāng)我們使用常規(guī)的內(nèi)存分配方式,比如 C++ 里的new、delete ,C 里的malloc、free ,每次申請(qǐng)的內(nèi)存塊大小不定。在頻繁操作下,就好比在一塊完整的土地上隨意挖坑(分配內(nèi)存)和填坑(釋放內(nèi)存) ,最后土地變得坑洼不平(內(nèi)存碎片化)。

在日常開發(fā)過程中,大家有沒有遇到過這樣的場(chǎng)景:程序在運(yùn)行時(shí)頻繁地進(jìn)行內(nèi)存分配與釋放操作 ,隨著時(shí)間的推移,程序的運(yùn)行速度越來越慢,內(nèi)存占用卻不斷攀升,甚至還可能出現(xiàn)內(nèi)存分配失敗的異常。這其實(shí)就是內(nèi)存分配過程中常見的性能問題和內(nèi)存碎片問題在作祟。

當(dāng)我們使用常規(guī)的內(nèi)存分配方式,比如 C++ 里的new、delete ,C 里的malloc、free ,每次申請(qǐng)的內(nèi)存塊大小不定。在頻繁操作下,就好比在一塊完整的土地上隨意挖坑(分配內(nèi)存)和填坑(釋放內(nèi)存) ,最后土地變得坑洼不平(內(nèi)存碎片化)。這些碎片化的內(nèi)存會(huì)導(dǎo)致后續(xù)的內(nèi)存分配操作效率降低,甚至在內(nèi)存總量充足的情況下,也可能因?yàn)闊o法找到連續(xù)的足夠大的內(nèi)存塊而導(dǎo)致分配失敗。

假設(shè)我們?cè)陂_發(fā)一個(gè)游戲,游戲中有大量的小對(duì)象頻繁地創(chuàng)建和銷毀,比如每一幀都要生成和刪除大量的子彈、特效粒子等。如果使用常規(guī)內(nèi)存分配方式,隨著游戲的運(yùn)行,內(nèi)存碎片會(huì)越來越多,最終可能導(dǎo)致游戲卡頓,嚴(yán)重影響玩家體驗(yàn)。那有沒有什么好的解決辦法呢?今天就給大家介紹一種高效的內(nèi)存管理方案 —— 定長(zhǎng)內(nèi)存池 ,它就像是一位貼心的管家,能夠幫助我們更合理地管理內(nèi)存,提升程序性能。

Part1.內(nèi)存池初印象

1.1什么是內(nèi)存池

內(nèi)存池,簡(jiǎn)單來說,就是在程序運(yùn)行前或者運(yùn)行初期,預(yù)先從操作系統(tǒng)申請(qǐng)一塊較大的連續(xù)內(nèi)存空間作為 “儲(chǔ)備庫(kù)” 。當(dāng)程序中需要分配內(nèi)存時(shí),不是直接向操作系統(tǒng)請(qǐng)求,而是從這個(gè)預(yù)先創(chuàng)建好的內(nèi)存池中獲??;當(dāng)程序釋放內(nèi)存時(shí),也不是立即歸還給操作系統(tǒng),而是將其放回內(nèi)存池,等待下一次被分配使用。

與常規(guī)的內(nèi)存分配方式相比,內(nèi)存池就像是一個(gè)有序的倉(cāng)庫(kù),而常規(guī)分配方式則像一個(gè)雜亂的集市。在集市里(常規(guī)內(nèi)存分配),每次買賣(內(nèi)存分配與釋放)的貨物(內(nèi)存塊)大小、位置都不固定,久而久之,集市就變得混亂不堪,難以找到合適的貨物(內(nèi)存碎片化) 。而在倉(cāng)庫(kù)(內(nèi)存池)中,貨物(內(nèi)存塊)被分類存放,需要時(shí)能快速找到并取用,歸還時(shí)也能準(zhǔn)確放回原位 ,極大地提高了效率。

內(nèi)存池最大的優(yōu)勢(shì)在于減少內(nèi)存碎片。由于內(nèi)存池中的內(nèi)存塊大小通常是固定的或者預(yù)先規(guī)劃好的,在頻繁的分配和釋放過程中,不會(huì)像常規(guī)分配那樣產(chǎn)生大量無法利用的小內(nèi)存碎片。這就好比將物品整齊地放在固定大小的貨架上(內(nèi)存塊規(guī)整排列) ,而不是隨意擺放,從而避免了空間的浪費(fèi)(減少內(nèi)存碎片) 。

內(nèi)存池的分配效率更高。常規(guī)內(nèi)存分配每次都需要與操作系統(tǒng)進(jìn)行交互,這涉及到復(fù)雜的系統(tǒng)調(diào)用和內(nèi)核操作,開銷較大。而內(nèi)存池的分配和釋放操作都在用戶態(tài)進(jìn)行,不需要頻繁陷入內(nèi)核,就像在自己家里找東西(內(nèi)存池內(nèi)分配)肯定比去商店買東西(向操作系統(tǒng)申請(qǐng)內(nèi)存)要快得多,大大節(jié)省了時(shí)間開銷,提高了程序的運(yùn)行速度。

總的來說,內(nèi)存池是一種強(qiáng)大的工具,它可以幫助我們更有效地管理內(nèi)存。但是,像所有工具一樣,我們需要理解它的優(yōu)點(diǎn)和缺點(diǎn),以便在適當(dāng)?shù)那闆r下使用它。

圖片圖片

1.2為什么需要內(nèi)存池

⑴內(nèi)存碎片問題

造成堆利用率很低的一個(gè)主要原因就是內(nèi)存碎片化。如果有未使用的存儲(chǔ)器,但是這塊存儲(chǔ)器不能用來滿足分配的請(qǐng)求,這時(shí)候就會(huì)產(chǎn)生內(nèi)存碎片化問題。內(nèi)存碎片化分為內(nèi)部碎片和外部碎片。

內(nèi)部碎片:內(nèi)部碎片是指一個(gè)已分配的塊比有效載荷大時(shí)發(fā)生的。(假設(shè)以前分配了10個(gè)大小的字節(jié),現(xiàn)在只用了5個(gè)字節(jié),則剩下的5個(gè)字節(jié)就會(huì)內(nèi)碎片)。內(nèi)部碎片的大小就是已經(jīng)分配的塊的大小和他們的有效載荷之差的和。因此內(nèi)部碎片取決于以前請(qǐng)求內(nèi)存的模式和分配器實(shí)現(xiàn)(對(duì)齊的規(guī)則)的模式。

外部碎片:假設(shè)系統(tǒng)依次分配了16byte、8byte、16byte、4byte,還剩余8byte未分配。這時(shí)要分配一個(gè)24byte的空間,操作系統(tǒng)回收了一個(gè)上面的兩個(gè)16byte,總的剩余空間有40byte,但是卻不能分配出一個(gè)連續(xù)24byte的空間,這就是外碎片問題。

圖片圖片

⑵申請(qǐng)效率問題

例如:我們上學(xué)家里給生活費(fèi)一樣,假設(shè)一學(xué)期的生活費(fèi)是6000塊。

  • 方式1:開學(xué)時(shí)6000塊直接給你,自己保管,自己分配如何花。
  • 方式2:每次要花錢時(shí),聯(lián)系父母,父母轉(zhuǎn)錢。

同樣是6000塊錢,第一種方式的效率肯定更高,因?yàn)榈诙N方式跟父母的溝通交互成本太高了。

同樣的道理,程序就像是上學(xué)的我們,操作系統(tǒng)就像父母,頻繁申請(qǐng)內(nèi)存的場(chǎng)景下,每次需要內(nèi)存,都像系統(tǒng)申請(qǐng)效率必然有影響。

Part2.定長(zhǎng)內(nèi)存池深度剖析

2.1核心原理

定長(zhǎng)內(nèi)存池的核心原理可以簡(jiǎn)單概括為:預(yù)先向操作系統(tǒng)申請(qǐng)一塊較大的連續(xù)內(nèi)存空間,然后將這塊大內(nèi)存按照固定的大小切割成多個(gè)小的內(nèi)存塊 。當(dāng)程序需要分配內(nèi)存時(shí),直接從這些預(yù)先切分好的固定大小的內(nèi)存塊中取出一個(gè)返回給程序使用;當(dāng)程序釋放內(nèi)存時(shí),將釋放的內(nèi)存塊重新回收到內(nèi)存池中,而不是立即歸還給操作系統(tǒng),以便后續(xù)再次分配使用。

以一個(gè)酒店為例,酒店就像是一個(gè)內(nèi)存池 ,酒店的房間就相當(dāng)于內(nèi)存塊。酒店在開業(yè)前(程序運(yùn)行前)就準(zhǔn)備好了一定數(shù)量的房間(申請(qǐng)大塊內(nèi)存并切分) 。當(dāng)有客人來入住(程序申請(qǐng)內(nèi)存)時(shí),直接分配一個(gè)空閑房間(內(nèi)存塊)給客人;當(dāng)客人退房(程序釋放內(nèi)存)時(shí),房間并不會(huì)立即拆除(內(nèi)存不還給系統(tǒng)) ,而是等待下一位客人入?。ㄏ乱淮蝺?nèi)存分配) 。這樣就避免了每次有客人來都要臨時(shí)建造房間(每次申請(qǐng)內(nèi)存都向操作系統(tǒng)請(qǐng)求)的麻煩,大大提高了效率。

假設(shè)我們要開發(fā)一個(gè)網(wǎng)絡(luò)通信程序,其中會(huì)頻繁地發(fā)送和接收固定大小的數(shù)據(jù)包,比如每個(gè)數(shù)據(jù)包大小為 1024 字節(jié)。如果使用常規(guī)內(nèi)存分配方式,每次發(fā)送或接收數(shù)據(jù)包都要向操作系統(tǒng)申請(qǐng)和釋放 1024 字節(jié)的內(nèi)存,開銷很大。而使用定長(zhǎng)內(nèi)存池,我們可以預(yù)先申請(qǐng)一大塊內(nèi)存,將其切分成多個(gè) 1024 字節(jié)的小塊。當(dāng)需要發(fā)送或接收數(shù)據(jù)包時(shí),直接從內(nèi)存池中獲取一個(gè) 1024 字節(jié)的內(nèi)存塊,使用完后再放回內(nèi)存池,極大地提高了內(nèi)存分配和釋放的效率,也減少了內(nèi)存碎片的產(chǎn)生。

2.2數(shù)據(jù)結(jié)構(gòu)構(gòu)建思路

實(shí)現(xiàn)定長(zhǎng)內(nèi)存池,通常需要用到以下幾種關(guān)鍵的數(shù)據(jù)結(jié)構(gòu):

  • 空閑內(nèi)存塊鏈表:這是一個(gè)非常重要的數(shù)據(jù)結(jié)構(gòu),用于管理內(nèi)存池中所有空閑的內(nèi)存塊。鏈表中的每個(gè)節(jié)點(diǎn)都代表一個(gè)空閑的內(nèi)存塊,節(jié)點(diǎn)中除了包含指向下一個(gè)空閑內(nèi)存塊的指針外,還可能包含一些用于標(biāo)識(shí)內(nèi)存塊狀態(tài)的信息。當(dāng)程序請(qǐng)求內(nèi)存時(shí),優(yōu)先從這個(gè)鏈表中取出空閑內(nèi)存塊進(jìn)行分配;當(dāng)程序釋放內(nèi)存時(shí),將釋放的內(nèi)存塊插入到這個(gè)鏈表中。它就像是酒店的空閑房間登記簿,記錄著所有空閑房間的信息,方便快速分配和回收房間。
  • 內(nèi)存池結(jié)構(gòu)體:用于記錄內(nèi)存池的整體狀態(tài)和參數(shù),比如指向大塊內(nèi)存起始地址的指針,記錄內(nèi)存池中空閑內(nèi)存塊鏈表頭指針,記錄內(nèi)存池剩余可用內(nèi)存大小的變量,以及內(nèi)存塊的固定大小等信息。這個(gè)結(jié)構(gòu)體就像是酒店的管理系統(tǒng),記錄著酒店的各種關(guān)鍵信息,如房間總數(shù)、空閑房間列表、酒店總?cè)萘康?,方便?duì)整個(gè)內(nèi)存池進(jìn)行管理和維護(hù)。

這些數(shù)據(jù)結(jié)構(gòu)之間相互協(xié)作,空閑內(nèi)存塊鏈表依賴于內(nèi)存池結(jié)構(gòu)體來獲取內(nèi)存池的基本信息,而內(nèi)存池結(jié)構(gòu)體通過空閑內(nèi)存塊鏈表來管理和維護(hù)內(nèi)存塊的分配與回收,共同實(shí)現(xiàn)了定長(zhǎng)內(nèi)存池的高效運(yùn)作。

2.3關(guān)鍵操作函數(shù)解析

實(shí)現(xiàn)定長(zhǎng)內(nèi)存池,離不開幾個(gè)關(guān)鍵的操作函數(shù):

  1. 初始化內(nèi)存池函數(shù):這個(gè)函數(shù)的主要功能是向操作系統(tǒng)申請(qǐng)大塊內(nèi)存,并對(duì)內(nèi)存池的各種數(shù)據(jù)結(jié)構(gòu)進(jìn)行初始化設(shè)置。在申請(qǐng)內(nèi)存時(shí),需要考慮內(nèi)存對(duì)齊等問題,以確保內(nèi)存的高效使用。同時(shí),要將申請(qǐng)到的大塊內(nèi)存按照固定大小切分成多個(gè)小內(nèi)存塊,并將這些小內(nèi)存塊組織成空閑內(nèi)存塊鏈表。比如在 C++ 中,我們可以使用malloc函數(shù)來申請(qǐng)大塊內(nèi)存,然后通過指針運(yùn)算將其切分成小內(nèi)存塊。初始化函數(shù)就像是酒店開業(yè)前的準(zhǔn)備工作,要準(zhǔn)備好房間、登記好房間信息等,為后續(xù)的運(yùn)營(yíng)做好鋪墊。
  2. 分配內(nèi)存函數(shù):當(dāng)程序調(diào)用這個(gè)函數(shù)申請(qǐng)內(nèi)存時(shí),它首先會(huì)檢查空閑內(nèi)存塊鏈表是否為空。如果鏈表不為空,說明有空閑的內(nèi)存塊可以直接分配,函數(shù)就從鏈表中取出一個(gè)空閑內(nèi)存塊返回給程序;如果鏈表為空,說明當(dāng)前內(nèi)存池中沒有空閑內(nèi)存塊了,此時(shí)需要判斷內(nèi)存池剩余的內(nèi)存空間是否足夠再分配一個(gè)固定大小的內(nèi)存塊。如果足夠,就從剩余內(nèi)存中分配一個(gè)內(nèi)存塊返回;如果不夠,就需要重新向操作系統(tǒng)申請(qǐng)大塊內(nèi)存,然后重復(fù)上述過程。在分配內(nèi)存時(shí),還需要注意一些邊界條件和錯(cuò)誤處理,比如內(nèi)存申請(qǐng)失敗的情況。它就像是酒店的前臺(tái)接待員,根據(jù)客人的需求分配空閑房間,如果沒有空閑房間,要判斷是否有可調(diào)配的房間或者是否需要增加房間。
  3. 釋放內(nèi)存函數(shù):當(dāng)程序不再使用某個(gè)內(nèi)存塊并調(diào)用這個(gè)函數(shù)釋放內(nèi)存時(shí),函數(shù)會(huì)將釋放的內(nèi)存塊重新插入到空閑內(nèi)存塊鏈表中。在插入之前,可能需要進(jìn)行一些額外的操作,比如檢查內(nèi)存塊的合法性,確保內(nèi)存塊確實(shí)是從當(dāng)前內(nèi)存池中分配出去的。同時(shí),還可能需要更新內(nèi)存池的一些狀態(tài)信息,如剩余可用內(nèi)存大小等。釋放內(nèi)存函數(shù)就像是酒店的退房處理流程,客人退房后,要將房間重新登記為空閑狀態(tài),以便下一位客人入住。

Part3.定長(zhǎng)內(nèi)存池實(shí)現(xiàn)

3.1核心成員變量剖析

要深入理解定長(zhǎng)內(nèi)存池的工作原理,首先得剖析其核心成員變量,它們就像是定長(zhǎng)內(nèi)存池這座大廈的基石,支撐著整個(gè)內(nèi)存管理體系的運(yùn)行。

以一個(gè)典型的定長(zhǎng)內(nèi)存池實(shí)現(xiàn)為例,通常會(huì)包含以下幾個(gè)關(guān)鍵的成員變量:

template <class T>
class ObjectPool {
public:
    // 省略其他成員函數(shù)...
private:
    char* _memory = nullptr; // 指向申請(qǐng)的大塊內(nèi)存
    size_t _remainBytes = 0; // 記錄剩余內(nèi)存字節(jié)數(shù)
    T* _freeList = nullptr;  // 管理歸還內(nèi)存的自由鏈表頭指針
};

_memory 是一個(gè)字符指針,它指向程序預(yù)先向操作系統(tǒng)申請(qǐng)的一大塊內(nèi)存。這一大塊內(nèi)存就像是一個(gè)大倉(cāng)庫(kù),后續(xù)所有的內(nèi)存分配和管理都基于它。之所以選擇字符指針,是因?yàn)樽址羔樏看我苿?dòng)的步長(zhǎng)是 1 字節(jié),非常靈活,便于我們對(duì)內(nèi)存進(jìn)行精細(xì)的操作,比如按字節(jié)粒度來切分內(nèi)存塊 。

_remainBytes 用于記錄當(dāng)前 _memory 所指向的大塊內(nèi)存中還剩余多少字節(jié)可供分配。在內(nèi)存分配過程中,每分配出一個(gè)固定大小的內(nèi)存塊,_remainBytes 的值就會(huì)相應(yīng)減少。通過這個(gè)變量,我們可以清楚地知道當(dāng)前內(nèi)存池中還有多少可用內(nèi)存,以便在需要時(shí)決定是否要重新向操作系統(tǒng)申請(qǐng)內(nèi)存。

_freeList 是一個(gè)指向自由鏈表頭部的指針。自由鏈表是定長(zhǎng)內(nèi)存池實(shí)現(xiàn)中的一個(gè)重要數(shù)據(jù)結(jié)構(gòu),它用于管理那些已經(jīng)被歸還但還未被再次分配的內(nèi)存塊。當(dāng)有內(nèi)存塊被釋放時(shí),它會(huì)被插入到自由鏈表中;當(dāng)有新的內(nèi)存分配請(qǐng)求時(shí),會(huì)優(yōu)先從自由鏈表中獲取內(nèi)存塊。這樣,通過自由鏈表,我們實(shí)現(xiàn)了內(nèi)存塊的復(fù)用,大大提高了內(nèi)存的使用效率 。

3.2內(nèi)存申請(qǐng)(New)流程詳解

當(dāng)程序需要從定長(zhǎng)內(nèi)存池中申請(qǐng)內(nèi)存時(shí),整個(gè)申請(qǐng)流程是精心設(shè)計(jì)的,旨在高效地滿足內(nèi)存需求。

①自由鏈表優(yōu)先:當(dāng)調(diào)用 New 函數(shù)申請(qǐng)內(nèi)存時(shí),定長(zhǎng)內(nèi)存池會(huì)首先檢查自由鏈表是否有可用的內(nèi)存塊。這就好比你去圖書館借書,會(huì)先看看圖書館的自助還書區(qū)有沒有你需要的書。如果自由鏈表不為空,說明有之前歸還的內(nèi)存塊可供使用,此時(shí)會(huì)采用頭刪的方式從自由鏈表中獲取一個(gè)內(nèi)存塊。具體實(shí)現(xiàn)如下:

T* New() {
    T* obj = nullptr;
    if (_freeList) {
        // 從自由鏈表頭刪一個(gè)對(duì)象
        void* next = *((void**)_freeList);
        obj = (T*)_freeList;
        _freeList = next;
        return obj;
    }
    // 后續(xù)處理大塊內(nèi)存分配...
}

通過這種方式,我們能夠快速地滿足內(nèi)存分配需求,避免了從大塊內(nèi)存中切分內(nèi)存塊的開銷,提高了內(nèi)存分配的效率。

②大塊內(nèi)存分配:如果自由鏈表中沒有可用的內(nèi)存塊,就需要從預(yù)先申請(qǐng)的大塊內(nèi)存中分配。首先,會(huì)判斷當(dāng)前大塊內(nèi)存中剩余的字節(jié)數(shù)(即 _remainBytes )是否足夠分配一個(gè)固定大小的內(nèi)存塊(大小為 sizeof(T) )。如果剩余字節(jié)數(shù)不足,就需要重新向操作系統(tǒng)申請(qǐng)一大塊內(nèi)存。申請(qǐng)內(nèi)存的函數(shù)通常會(huì)封裝系統(tǒng)調(diào)用,例如在 Windows 下可以使用 VirtualAlloc 函數(shù),在 Linux 下可以使用 brk 或 mmap 函數(shù)。

if (_remainBytes < sizeof(T)) {
    _remainBytes = 128 * 1024; // 重新申請(qǐng)內(nèi)存,這里以申請(qǐng)128KB為例
    _memory = (char*)malloc(_remainBytes);
    if (_memory == nullptr) {
        throw std::bad_alloc(); // 內(nèi)存申請(qǐng)失敗,拋出異常
    }
}

申請(qǐng)到新的大塊內(nèi)存后,會(huì)從這塊內(nèi)存中分配出一個(gè)內(nèi)存塊給調(diào)用者,并相應(yīng)地調(diào)整 _memory 指針的指向和 _remainBytes 的值。

obj = (T*)_memory;
_memory += sizeof(T);
_remainBytes -= sizeof(T);

最后,使用定位 new(placement new)來初始化對(duì)象,調(diào)用對(duì)象的構(gòu)造函數(shù),使分配的內(nèi)存塊成為一個(gè)可用的對(duì)象。

new(obj)T;
return obj;

這樣,通過自由鏈表優(yōu)先和大塊內(nèi)存分配相結(jié)合的方式,定長(zhǎng)內(nèi)存池能夠高效地滿足程序的內(nèi)存申請(qǐng)需求。

3.3內(nèi)存釋放(Delete)流程詳解

當(dāng)程序不再需要某個(gè)對(duì)象,調(diào)用 Delete 函數(shù)釋放內(nèi)存時(shí),定長(zhǎng)內(nèi)存池的內(nèi)存釋放流程也有其獨(dú)特的步驟。

首先,會(huì)調(diào)用對(duì)象的析構(gòu)函數(shù),清理對(duì)象內(nèi)部的資源,確保對(duì)象的狀態(tài)是安全可回收的。這一步非常重要,就像你歸還圖書館的書之前,要確保書的內(nèi)容完整,沒有缺失頁(yè)或損壞。

void Delete(T* obj) {
    obj->~T(); // 調(diào)用對(duì)象的析構(gòu)函數(shù)
    // 后續(xù)將對(duì)象插回自由鏈表...
}

然后,將釋放的對(duì)象頭插回自由鏈表中。在將對(duì)象插回自由鏈表時(shí),需要注意不同平臺(tái)下指針大小的差異。在 32 位系統(tǒng)中,指針大小通常為 4 字節(jié);在 64 位系統(tǒng)中,指針大小通常為 8 字節(jié)。為了處理這種差異,我們可以使用二級(jí)指針解引用的方式。具體來說,將對(duì)象指針轉(zhuǎn)換為二級(jí)指針(T** ),然后進(jìn)行解引用操作。這樣,無論在 32 位還是 64 位系統(tǒng)中,解引用操作都會(huì)正確地處理指針大小,將對(duì)象正確地插入自由鏈表。

*((T**)obj) = _freeList;
_freeList = obj;

通過這種方式,釋放的內(nèi)存塊被重新納入自由鏈表的管理,以便后續(xù)再次被分配使用。這種內(nèi)存釋放流程不僅保證了內(nèi)存的正確回收和復(fù)用,還巧妙地處理了不同平臺(tái)下指針大小的兼容性問題,使得定長(zhǎng)內(nèi)存池的實(shí)現(xiàn)更加健壯和通用 。

Part4.代碼實(shí)戰(zhàn)與性能驗(yàn)證

4.1代碼示例展示

下面是一個(gè)完整的定長(zhǎng)內(nèi)存池的 C++ 實(shí)現(xiàn)代碼,通過這個(gè)代碼示例,我們能更直觀地理解定長(zhǎng)內(nèi)存池的工作機(jī)制。代碼中關(guān)鍵部分都添加了詳細(xì)注釋,幫助大家理解每一步的操作。

#include <iostream>
#include <vector>

template <class T>
class ObjectPool {
public:
    T* New() {
        T* obj = nullptr;
        // 優(yōu)先從自由鏈表獲取內(nèi)存塊
        if (_freeList) {
            void* next = *((void**)_freeList);
            obj = (T*)_freeList;
            _freeList = next;
        } 
        else {
            // 剩余內(nèi)存不足時(shí),重新申請(qǐng)大塊內(nèi)存
            if (_remainBytes < sizeof(T)) {
                _remainBytes = 128 * 1024; // 申請(qǐng)128KB內(nèi)存,可根據(jù)需求調(diào)整
                _memory = (char*)malloc(_remainBytes);
                if (_memory == nullptr) {
                    throw std::bad_alloc();
                }
            }
            obj = (T*)_memory;
            _memory += sizeof(T);
            _remainBytes -= sizeof(T);
        }
        // 使用定位new初始化對(duì)象
        new(obj)T;
        return obj;
    }

    void Delete(T* obj) {
        // 調(diào)用對(duì)象析構(gòu)函數(shù)
        obj->~T();
        // 將釋放的對(duì)象插回自由鏈表
        *((T**)obj) = _freeList;
        _freeList = obj;
    }

private:
    char* _memory = nullptr; // 指向申請(qǐng)的大塊內(nèi)存
    size_t _remainBytes = 0; // 記錄剩余內(nèi)存字節(jié)數(shù)
    T* _freeList = nullptr;  // 管理歸還內(nèi)存的自由鏈表頭指針
};

// 測(cè)試用的簡(jiǎn)單結(jié)構(gòu)體
struct TestStruct {
    int data;
    TestStruct() : data(0) {}
};

int main() {
    ObjectPool<TestStruct> pool;
    std::vector<TestStruct*> objects;

    // 申請(qǐng)內(nèi)存塊
    for (size_t i = 0; i < 10; ++i) {
        TestStruct* obj = pool.New();
        objects.push_back(obj);
    }

    // 釋放內(nèi)存塊
    for (size_t i = 0; i < 10; ++i) {
        pool.Delete(objects[i]);
    }

    return 0;
}

在這段代碼中,ObjectPool類實(shí)現(xiàn)了定長(zhǎng)內(nèi)存池的基本功能。New函數(shù)負(fù)責(zé)內(nèi)存的申請(qǐng),首先檢查自由鏈表中是否有可用內(nèi)存塊,如果有則直接使用;若沒有則從預(yù)先申請(qǐng)的大塊內(nèi)存中分配,當(dāng)大塊內(nèi)存不足時(shí),會(huì)重新申請(qǐng)。Delete函數(shù)負(fù)責(zé)內(nèi)存的釋放,先調(diào)用對(duì)象的析構(gòu)函數(shù)清理資源,然后將對(duì)象插回自由鏈表 。TestStruct結(jié)構(gòu)體用于測(cè)試內(nèi)存池的功能,在main函數(shù)中,我們通過循環(huán)申請(qǐng)和釋放內(nèi)存塊,驗(yàn)證定長(zhǎng)內(nèi)存池的正確性 。

4.2性能測(cè)試與結(jié)果分析

為了驗(yàn)證定長(zhǎng)內(nèi)存池的性能優(yōu)勢(shì),我們?cè)O(shè)計(jì)了一個(gè)性能測(cè)試實(shí)驗(yàn),對(duì)比系統(tǒng)自帶內(nèi)存分配(new和delete)和定長(zhǎng)內(nèi)存池(ObjectPool的New和Delete)在多次申請(qǐng)和釋放內(nèi)存時(shí)的時(shí)間開銷。

測(cè)試代碼如下:

#include <iostream>
#include <vector>
#include <chrono>

// 引入前面定義的ObjectPool類和TestStruct結(jié)構(gòu)體

// 測(cè)試系統(tǒng)自帶內(nèi)存分配
void testSystemAllocation() {
    auto start = std::chrono::high_resolution_clock::now();
    std::vector<TestStruct*> objects;
    for (size_t i = 0; i < 100000; ++i) {
        TestStruct* obj = new TestStruct;
        objects.push_back(obj);
    }
    for (size_t i = 0; i < 100000; ++i) {
        delete objects[i];
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    std::cout << "System allocation time: " << duration << " ms" << std::endl;
}

// 測(cè)試定長(zhǎng)內(nèi)存池分配
void testObjectPoolAllocation() {
    ObjectPool<TestStruct> pool;
    auto start = std::chrono::high_resolution_clock::now();
    std::vector<TestStruct*> objects;
    for (size_t i = 0; i < 100000; ++i) {
        TestStruct* obj = pool.New();
        objects.push_back(obj);
    }
    for (size_t i = 0; i < 100000; ++i) {
        pool.Delete(objects[i]);
    }
    auto end = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
    std::cout << "Object pool allocation time: " << duration << " ms" << std::endl;
}

int main() {
    testSystemAllocation();
    testObjectPoolAllocation();
    return 0;
}

在這個(gè)測(cè)試中,我們分別進(jìn)行了 100000 次內(nèi)存的申請(qǐng)和釋放操作,使用std::chrono庫(kù)來精確測(cè)量時(shí)間。通過多次運(yùn)行測(cè)試代碼,得到如下結(jié)果(實(shí)際結(jié)果可能因機(jī)器性能和編譯器不同而有所差異):

測(cè)試類型

時(shí)間開銷(ms)

系統(tǒng)自帶內(nèi)存分配

1200

定長(zhǎng)內(nèi)存池分配

350

從結(jié)果可以明顯看出,定長(zhǎng)內(nèi)存池在多次申請(qǐng)和釋放內(nèi)存時(shí)的時(shí)間開銷遠(yuǎn)遠(yuǎn)低于系統(tǒng)自帶的內(nèi)存分配方式。這是因?yàn)槎ㄩL(zhǎng)內(nèi)存池減少了系統(tǒng)調(diào)用次數(shù),避免了內(nèi)存碎片問題,并且通過自由鏈表實(shí)現(xiàn)了內(nèi)存塊的高效復(fù)用,從而大大提高了內(nèi)存分配和釋放的效率,在性能要求較高的場(chǎng)景中具有顯著優(yōu)勢(shì) 。

責(zé)任編輯:武曉燕 來源: 深度Linux
相關(guān)推薦

2025-08-01 01:55:00

2025-06-09 04:00:00

2025-08-05 09:24:30

2013-11-07 09:42:42

對(duì)象對(duì)象池加速

2025-04-22 03:00:00

2025-08-11 01:00:00

2021-07-14 10:00:32

Python內(nèi)存測(cè)量

2013-10-12 13:01:51

Linux運(yùn)維內(nèi)存管理

2010-09-25 14:12:50

Java內(nèi)存分配

2023-10-18 13:31:00

Linux內(nèi)存

2022-03-07 10:54:34

內(nèi)存Linux

2021-02-28 13:22:54

Java內(nèi)存代碼

2022-03-16 08:39:19

StackHeap內(nèi)存

2009-06-03 15:52:34

堆內(nèi)存棧內(nèi)存Java內(nèi)存分配

2013-10-12 11:15:09

Linux運(yùn)維內(nèi)存管理

2019-07-31 10:08:19

人工多線程數(shù)據(jù)

2022-01-13 10:30:21

C語言內(nèi)存動(dòng)態(tài)

2018-02-08 14:57:22

對(duì)象內(nèi)存分配

2011-07-15 01:10:13

C++內(nèi)存分配

2021-12-16 06:52:33

C語言內(nèi)存分配
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

欧美一级久久久久久久大片| 国产女主播视频一区二区| 欧美日韩999| jizz欧美性20| 亚洲国产天堂| 午夜影院在线观看欧美| 视频一区二区在线| 北条麻妃一二三区| 三级久久三级久久| 日韩一区二区欧美| 特级西西人体4444xxxx| 日本免费成人| 狠狠躁夜夜躁人人爽天天天天97| 一区二区三区欧美成人| 少妇精品视频一区二区| 久久99精品国产.久久久久久| 97涩涩爰在线观看亚洲| 特级西西人体高清大胆| 欧美一区二区三区红桃小说| 欧美久久久一区| av之家在线观看| a视频在线播放| 91视频在线观看免费| 91欧美日韩一区| 小泽玛利亚一区二区三区视频| 欧美福利专区| 色妞色视频一区二区三区四区| 香蕉视频污视频| 国产情侣一区在线| 欧美三级电影网站| 一本久道中文无码字幕av| 成人国产免费电影| 国产精品视频第一区| 免费av一区二区三区| 精品人妻一区二区三区浪潮在线 | 国产一区二区三区视频在线| 日韩欧美国产黄色| 丁香花在线影院观看在线播放| 免费av网站在线看| 国产精品麻豆网站| 亚洲巨乳在线观看| 成人av一区| 国产三级精品三级在线专区| 精品欧美一区二区精品久久| 免费av一级片| 成人国产一区二区三区精品| 粉嫩av四季av绯色av第一区| av中文字幕免费在线观看| 久久成人麻豆午夜电影| 国产主播精品在线| 一道本在线视频| 美腿丝袜一区二区三区| 国产精品久久久久久久久久尿 | 国产精品18在线| 精品国产一区二区三区av片| 亚洲男人av在线| 一级性生活毛片| 亚洲自拍都市欧美小说| 日韩二区三区在线| 久操视频免费看| 精品国产99| 中文字幕在线观看亚洲| 丁香六月激情综合| 午夜片欧美伦| 欧美黄网免费在线观看| 国产午夜激情视频| 国产精品久久久一区二区| 日韩av免费在线播放| 日韩精选在线观看| 激情综合色播五月| http;//www.99re视频| 二区三区在线视频| 久久亚洲影视婷婷| 杨幂一区欧美专区| 中文字幕有码在线观看| 午夜成人免费电影| 凹凸日日摸日日碰夜夜爽1| 欧美电影在线观看网站| 欧美一区二区三区色| 亚洲性图第一页| 日韩欧美在线精品| 按摩亚洲人久久| 久久免费少妇高潮99精品| 亚洲电影在线| 国产精品亚洲激情| 成人午夜免费在线观看| 国产亚洲欧洲997久久综合| 少妇精品久久久久久久久久| 草莓福利社区在线| 粉嫩老牛aⅴ一区二区三区| 天美星空大象mv在线观看视频| 精品国产亚洲一区二区在线观看| 亚洲国产欧美日韩精品| 一本在线免费视频| 亚洲美女视频在线免费观看| 国产不卡av在线| 精品人妻午夜一区二区三区四区 | 在线视频精品一区| 91豆花视频在线播放| 欧美在线一区二区三区| 久久久久亚洲av无码麻豆| 日韩欧美天堂| 欧美高清视频一区二区| 国产精品51麻豆cm传媒 | 动漫精品视频| 国产三级在线免费| 亚洲国产一区二区三区| 久久99999| 日韩电影在线观看完整免费观看| www.日韩.com| 69视频免费在线观看| 国产电影一区二区三区| 图片区小说区区亚洲五月| f2c人成在线观看免费视频| 欧美精三区欧美精三区| 国产精品无码午夜福利| 国产一区欧美| 成人免费午夜电影| 懂色一区二区三区| 第一福利永久视频精品| 稀缺呦国内精品呦| 亚洲国产一区二区在线观看 | 电影中文字幕一区二区| 一个色综合导航| 亚洲欧美一区二区三区在线观看| 国产精品18久久久久久vr| 亚洲一区二区三区免费看| 周于希免费高清在线观看| 精品久久一区二区| 国产suv一区二区三区| 欧美a级理论片| 欧美二区在线| 欧美大片高清| 亚洲欧美日韩网| 欧美啪啪小视频| 不卡区在线中文字幕| www.国产在线视频| 日韩中文字幕一区二区高清99| 日韩在线国产精品| 一级黄色片在线播放| 中文字幕免费观看一区| 一级黄色香蕉视频| 日本电影一区二区| 国产精品偷伦视频免费观看国产 | 午夜精品三级视频福利| 亚洲男人第一天堂| 亚洲国产一区视频| 日韩aaaaa| 亚洲一区亚洲| 欧美日韩亚洲综合一区二区三区激情在线| free性m.freesex欧美| 亚洲国产精品va在线看黑人动漫| 伊人国产在线观看| 91在线观看下载| 久久无码高潮喷水| 深夜福利久久| 国产日产久久高清欧美一区| 久草中文在线| 精品蜜桃在线看| 日韩av在线播| 久久久久久久电影| 亚洲 欧美 另类人妖| 久久人体视频| 亚洲自拍小视频免费观看| 激情av在线| 日韩精品视频在线| 中文字幕乱码视频| 亚洲欧美一区二区三区极速播放 | jizz性欧美23| 国模叶桐国产精品一区| 日韩av高清在线| 欧美色图免费看| 国产第一页浮力| 成人精品视频网站| 久久精品视频91| 亚洲精品一区二区在线看| 99porn视频在线| 欧美电影免费看| 久久成人一区二区| 亚洲 另类 春色 国产| 欧美在线免费观看亚洲| 国产极品国产极品| 91一区在线观看| 日本高清久久久| 91久久在线| 亚洲精品影院| 国产精品巨作av| 国产精品一区二区三区久久久| 伊人手机在线| 一道本无吗dⅴd在线播放一区 | 17c丨国产丨精品视频| 美女av一区| 91精品久久久久久久久| 国产精选在线| 久久精品在线视频| 水莓100在线视频| 欧美一级xxx| 精品无码一区二区三区的天堂| 日韩一区在线看| 亚洲最大的黄色网| 国产一区二区三区综合| 国产精品视频一区二区三区四区五区 | 678五月天丁香亚洲综合网| 999这里只有精品| 亚洲美女视频一区| 91麻豆制片厂| 99精品国产一区二区三区不卡| 国产福利精品一区二区三区| 亚洲一区视频| 成人午夜视频在线观看免费| 亚洲深深色噜噜狠狠爱网站| 欧美三级电影在线播放| 成人h动漫精品一区二区器材| 国产在线视频欧美| 992tv国产精品成人影院| 97在线看福利| 国产丝袜视频在线播放| 久久精品国产一区二区电影| 邻居大乳一区二区三区| 亚洲丁香婷深爱综合| 国产极品999| 欧美日韩国产bt| 国产成人精品亚洲| 色婷婷av一区二区三区之一色屋| 日本熟妇乱子伦xxxx| 亚洲免费观看高清| 日韩一卡二卡在线观看| 日本一区二区三区免费乱视频| 免费成人深夜夜行p站| 成人午夜av电影| 女同性αv亚洲女同志| 国产米奇在线777精品观看| 久久撸在线视频| 奇米影视一区二区三区小说| 白嫩少妇丰满一区二区| 亚洲一区日韩在线| 黄色动漫网站入口| 久久九九免费| 色婷婷综合久久久久中文字幕| 亚洲欧美久久久| 日日摸天天爽天天爽视频| 免费视频一区| 日日碰狠狠丁香久燥| 水蜜桃久久夜色精品一区的特点| 国产免费黄色av| 免费久久99精品国产自在现线| 欧美久久久久久久久久久久久| 亚洲人妖在线| 97国产在线播放| 视频一区在线播放| 韩国视频一区二区三区| 日本成人超碰在线观看| www.国产视频.com| 精品一区二区三区影院在线午夜| 亚洲理论中文字幕| 国产裸体歌舞团一区二区| 亚洲熟女乱综合一区二区| 成人夜色视频网站在线观看| 自拍视频一区二区| 久久久久国色av免费看影院| 精品丰满少妇一区二区三区| 日韩理论片在线| 久久久精品人妻一区二区三区四| 亚洲一区二区五区| 天干夜夜爽爽日日日日| 欧美亚洲动漫另类| 国产免费不卡av| 337p日本欧洲亚洲大胆色噜噜| 三级av在线播放| 中文字幕国产亚洲2019| 成人毛片av在线| 2019国产精品自在线拍国产不卡| 偷拍精品精品一区二区三区| 成人欧美一区二区三区在线湿哒哒| 麻豆一二三区精品蜜桃| 精品国产乱码久久久久久88av | 9191国产视频| 999亚洲国产精| 中文字幕国产免费| 丁香啪啪综合成人亚洲小说 | 亚洲一区二区三区四区在线 | 亚洲国产一区二区三区在线观看| 日本一卡二卡四卡精品| 日韩视频亚洲视频| 97超碰免费在线| 国产精品免费在线免费 | 欧美在线视频第一页| 亚洲成人高清在线| 日韩国产亚洲欧美| 日韩精品专区在线影院重磅| 欧美成人片在线| 久久99国产精品自在自在app| 欧美男人天堂| 96久久精品| 大片网站久久| 你懂的av在线| 国产在线播放一区三区四| 日韩精品卡通动漫网站| 亚洲人精品午夜| 国产一级片免费视频| 精品久久五月天| 伦xxxx在线| 国产精品www网站| 麻豆一区一区三区四区| 福利在线小视频| 捆绑变态av一区二区三区| 黄色工厂在线观看| 亚洲主播在线播放| 88av在线视频| 国产亚洲精品美女久久久久 | 国产美女久久精品| 网曝91综合精品门事件在线| 国产传媒久久久| 久久精品国产亚洲a| 一区二区伦理片| 欧美视频在线免费| 日本波多野结衣在线| 久久久精品一区二区| 国产极品嫩模在线观看91精品| 久久综合中文色婷婷| 亚洲特色特黄| 美女流白浆视频| 亚洲欧洲综合另类在线| 在线观看亚洲国产| 在线日韩日本国产亚洲| 欧美大片免费观看网址| 久久久久久久久久久一区 | 综合久久综合久久| 影音先锋国产资源| 在线播放国产精品| 91精品韩国| 日本不卡免费新一二三区| 国产日韩欧美一区二区三区在线观看| 人妻互换一二三区激情视频| 亚洲女女做受ⅹxx高潮| 国产巨乳在线观看| 不卡中文字幕av| 国产精品日本一区二区不卡视频| 一区二区三区国| 激情久久久久久久久久久久久久久久| 国产熟女一区二区| 欧美三级蜜桃2在线观看| av免费观看一区二区| 国产精品一二三视频| 色喇叭免费久久综合| av免费一区二区| 亚洲精品一卡二卡| www.97超碰| 国内精品400部情侣激情| 国产精品视屏| 成年人观看网站| 欧美国产日产图区| 一级片aaaa| 欧美成在线视频| 韩国精品福利一区二区三区| 欧美日韩成人免费视频| 久久在线观看免费| 国产在线一级片| 久久中文字幕在线| 久久夜色电影| www日韩视频| 中文字幕日韩av资源站| 亚洲AV无码精品色毛片浪潮| 久久久久久国产精品美女| 日韩av系列| 美女黄色片视频| 亚洲欧美日韩在线播放| 亚洲国产精品国自产拍久久| 91精品国产91久久久久| 国产成人精品免费视| 婷婷中文字幕在线观看| 亚洲高清三级视频| 国产一二在线观看| 成人中心免费视频| 日韩亚洲精品在线| 大胸美女被爆操| 精品久久久久久久久久久久久久久久久| а√天堂中文资源在线bt| 欧美一区免费视频| 激情五月激情综合网| 日韩久久久久久久久| 国产一区二区精品丝袜| 精品一区视频| 免费观看日韩毛片| 亚洲欧美日韩在线| 四虎在线免费看| 成人午夜小视频| 亚洲一区二区三区四区五区午夜 | 黄色a一级视频| 在线播放国产精品二区一二区四区 | 青青草综合网| 国产伦精品一区二区三区88av| 精品国产电影一区| av在线免费观看网址| 欧美午夜精品理论片a级大开眼界 欧美午夜精品久久久久免费视 | 26uuu日韩精品一区二区| 久久亚洲专区| 青青草视频成人| 欧美大片在线观看一区二区| 久久电影tv|