日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

两种内存池管理方法对比

發(fā)布時間:2024/1/1 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 两种内存池管理方法对比 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?

一、問題背景

最近在調(diào)試ambiq apollo3的藍(lán)牙時,其使用了ARM Cordio WSF的藍(lán)牙協(xié)議棧。通過學(xué)習(xí)wsf_buf.c的實現(xiàn),看到了一種不同于固定大小內(nèi)存塊的內(nèi)存池管理方式。它使用了可變大小的內(nèi)存塊分配,支持內(nèi)存塊大小自定義。為了學(xué)習(xí)其內(nèi)存管理思想,故特此記錄下這兩種內(nèi)存池管理方式的差異。本文將分別介紹了這兩種內(nèi)存池管理方法的實現(xiàn)方式,最后對比兩種方式的優(yōu)缺點和適用場景。

?

二、兩種內(nèi)存池管理

2.1 固定大小內(nèi)存塊分配(參考正點原子STM32F4 malloc.c)

固定大小內(nèi)存塊的方式,簡單的說就是將內(nèi)存按照相同大小劃分成若干個內(nèi)存塊。每一個內(nèi)存塊有一個對應(yīng)的內(nèi)存管理表。如果對應(yīng)的內(nèi)存管理表為0,則標(biāo)志未使用。非零表示此內(nèi)存已經(jīng)被分配使用中。

分塊式內(nèi)存管理由內(nèi)存池和內(nèi)存管理表兩部分組成。內(nèi)存池被等分為 n塊,對應(yīng)的內(nèi)存管理表,大小也為 n,內(nèi)存管理表的每一個項對應(yīng)內(nèi)存池的一塊內(nèi)存。

內(nèi)存管理表的項值代表的意義為:當(dāng)該項值為 0 的時候,代表對應(yīng)的內(nèi)存塊未被占用,當(dāng)該項值非零的時候,代表該項對應(yīng)的內(nèi)存塊已經(jīng)被占用,其數(shù)值則代表被連續(xù)占用的內(nèi)存塊數(shù)。比如某項值為 10,那么說明包括本項對應(yīng)的內(nèi)存塊在內(nèi),總共分配了 10 個內(nèi)存塊給外部的某個指針。

內(nèi)寸分配方向如圖所示,是從頂->底的分配方向。即首先從最末端開始找空內(nèi)存。當(dāng)內(nèi)存管理剛初始化的時候,內(nèi)存表全部清零,表示沒有任何內(nèi)存塊被占用。

? ? ? ? ? ? ? ? ? ? ???

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖1 內(nèi)存塊物理上分布圖

2.1.1 初始化

在移植這種內(nèi)存池分配前,我們需要預(yù)先定義待分配的內(nèi)存物理地址和內(nèi)存塊大小。如下所示,在STM32F4 MCU中我們有內(nèi)部SRAM、內(nèi)部CCRAM和外部SRAM,共三處內(nèi)存。通過MEMx_BLOCK_SIZE定義內(nèi)存塊的大小,我們這里將這三處內(nèi)存都設(shè)置為32byte。

MEMx_MAX_SIZE表示內(nèi)存管理大小。而內(nèi)存表由于和內(nèi)存一一對應(yīng),故MEMx_MAX_SIZE/MEMx_BLOCK_SIZE就能得到實際的內(nèi)存表大小(個數(shù))。

//malloc.h 頭文件定義: //mem1內(nèi)存參數(shù)設(shè)定.mem1完全處于內(nèi)部SRAM里面. #define MEM1_BLOCK_SIZE 32 //內(nèi)存塊大小為32字節(jié) #define MEM1_MAX_SIZE 20*1024 //最大管理內(nèi)存 100K #define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //內(nèi)存表大小//mem2內(nèi)存參數(shù)設(shè)定.mem2處于CCM,用于管理CCM(特別注意,這部分SRAM,僅CPU可以訪問!!) #define MEM2_BLOCK_SIZE 32 //內(nèi)存塊大小為32字節(jié) #define MEM2_MAX_SIZE 60 *1024 //最大管理內(nèi)存60K #define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE //內(nèi)存表大小//mem3內(nèi)存參數(shù)設(shè)定.mem3的內(nèi)存池處于外部SRAM里面 #define MEM3_BLOCK_SIZE 32 //內(nèi)存塊大小為32字節(jié) #define MEM3_MAX_SIZE 960 *1024 //最大管理內(nèi)存960K #define MEM3_ALLOC_TABLE_SIZE MEM3_MAX_SIZE/MEM3_BLOCK_SIZE //內(nèi)存表大小// malloc.c源碼定義 //內(nèi)存池(32字節(jié)對齊) __align(32) u8 mem1base[MEM1_MAX_SIZE]; //內(nèi)部SRAM內(nèi)存池 __align(32) u8 mem2base[MEM2_MAX_SIZE] __attribute__((at(0X10000000))); //內(nèi)部CCM內(nèi)存池 __align(32) u8 mem3base[MEM3_MAX_SIZE] __attribute__((at(0X68000000))); //外部SRAM內(nèi)存池 //內(nèi)存管理表 u16 mem1mapbase[MEM1_ALLOC_TABLE_SIZE]; //內(nèi)部SRAM內(nèi)存池MAP u16 mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X10000000+MEM2_MAX_SIZE))); //內(nèi)部CCM內(nèi)存池MAP u16 mem3mapbase[MEM3_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM3_MAX_SIZE))); //外部SRAM內(nèi)存池MAP //內(nèi)存管理參數(shù) const u32 memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE,MEM3_ALLOC_TABLE_SIZE};//內(nèi)存表大小 const u32 memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE,MEM3_BLOCK_SIZE};//內(nèi)存分塊大小 const u32 memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE,MEM3_MAX_SIZE};

初始化時,只用將內(nèi)存池和內(nèi)存管理表都清零即可。

//內(nèi)存管理初始化 //memx:所屬內(nèi)存塊 void my_mem_init(u8 memx) { mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//內(nèi)存狀態(tài)表數(shù)據(jù)清零 mymemset(mallco_dev.membase[memx], 0,memsize[memx]);//內(nèi)存池所有數(shù)據(jù)清零 mallco_dev.memrdy[memx]=1; //內(nèi)存管理初始化OK }

2.1.2 分配原理

當(dāng)指針 p 調(diào)用 malloc 申請內(nèi)存的時候,先判斷 p 要分配的內(nèi)存塊數(shù)(m),然后從第 n 項開始,向下查找,直到找到 m 塊連續(xù)的空內(nèi)存塊(即對應(yīng)內(nèi)存管理表項為 0),然后將這 m 個內(nèi)存管理表項的值都設(shè)置為 m(標(biāo)記被占用),最后,把最后的這個空內(nèi)存塊的地址返回指針 p,完成一次分配。注意,如果當(dāng)內(nèi)存不夠的時候(找到最后也沒找到連續(xù)的 m 塊空閑內(nèi)存),則返回 NULL 給 p,表示分配失敗。

//內(nèi)存分配(內(nèi)部調(diào)用) //memx:所屬內(nèi)存塊 //size:要分配的內(nèi)存大小(字節(jié)) //返回值:0XFFFFFFFF,代表錯誤;其他,內(nèi)存偏移地址 u32 my_mem_malloc(u8 memx,u32 size) { signed long offset=0; u32 nmemb; //需要的內(nèi)存塊數(shù) u32 cmemb=0;//連續(xù)空內(nèi)存塊數(shù)u32 i; if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先執(zhí)行初始化 if(size==0)return 0XFFFFFFFF;//不需要分配nmemb=size/memblksize[memx]; //獲取需要分配的連續(xù)內(nèi)存塊數(shù)if(size%memblksize[memx])nmemb++; for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整個內(nèi)存控制區(qū)(每次都要從頭開始搜索,而且不排序,效率低--yulong) {if(!mallco_dev.memmap[memx][offset]){cmemb++;//連續(xù)空內(nèi)存塊數(shù)增加(為0)}else {cmemb=0;} //連續(xù)內(nèi)存塊清零if(cmemb==nmemb) //找到了連續(xù)nmemb個空內(nèi)存塊{for(i=0;i<nmemb;i++) //標(biāo)注內(nèi)存塊非空 (每次申請,釋放都要標(biāo)記,效率低.不如鏈表高效 --yulong){ mallco_dev.memmap[memx][offset+i]=nmemb; } return (offset*memblksize[memx]);//返回偏移地址 }} return 0XFFFFFFFF;//未找到符合分配條件的內(nèi)存塊 } //分配內(nèi)存(外部調(diào)用) //memx:所屬內(nèi)存塊 //size:內(nèi)存大小(字節(jié)) //返回值:分配到的內(nèi)存首地址. void *mymalloc(u8 memx,u32 size) { u32 offset;offset=my_mem_malloc(memx,size); if(offset==0XFFFFFFFF)return NULL; else return (void*)((u32)mallco_dev.membase[memx]+offset); //返回字節(jié) }

2.1.3?釋放原理

當(dāng) p 申請的內(nèi)存用完,需要釋放的時候,調(diào)用 free 函數(shù)實現(xiàn)。 free 函數(shù)先判斷 p 指向的內(nèi)存地址所對應(yīng)的內(nèi)存塊,然后找到對應(yīng)的內(nèi)存管理表項目,得到 p 所占用的內(nèi)存塊數(shù)目 m(內(nèi)存管理表項目的值就是所分配內(nèi)存塊的數(shù)目),將這 m 個內(nèi)存管理表項目的值都清零,標(biāo)記釋放,完成一次內(nèi)存釋放。

//釋放內(nèi)存(內(nèi)部調(diào)用) //memx:所屬內(nèi)存塊 //offset:內(nèi)存地址偏移 //返回值:0,釋放成功;1,釋放失敗; u8 my_mem_free(u8 memx,u32 offset) { int i; if(!mallco_dev.memrdy[memx])//未初始化,先執(zhí)行初始化{mallco_dev.init(memx); return 1;//未初始化 } if(offset<memsize[memx])//偏移在內(nèi)存池內(nèi). { int index=offset/memblksize[memx]; //找到偏移所在內(nèi)存塊號碼 。int nmemb=mallco_dev.memmap[memx][index]; //得到,內(nèi)存塊數(shù)量for(i=0;i<nmemb;i++) //內(nèi)存塊清零{ mallco_dev.memmap[memx][index+i]=0; } return 0; }else return 2;//偏移超區(qū)了. } //釋放內(nèi)存(外部調(diào)用) //memx:所屬內(nèi)存塊 //ptr:內(nèi)存首地址 u8 myfree(u8 memx,void *ptr) {u8 res=0;u32 offset; if(ptr==NULL) return 3;//地址為0. offset=(u32)ptr-(u32)mallco_dev.membase[memx]; res = my_mem_free(memx,offset); //釋放內(nèi)存 return res; }

2.2 可變大小內(nèi)存塊分配(參考WSF BLE協(xié)議棧buffer management)

可見,上面固定大小內(nèi)存塊方式在查找和釋放時,都需要遍歷、置/清內(nèi)存表標(biāo)志位,比較費時間。而可變大小內(nèi)存塊的思想是:將待分配的內(nèi)存分為大、中、小這么幾類。每一類由相同大小的內(nèi)存塊通過一個單鏈表鏈接在一起組成。初始化后,空閑鏈表*pFree就指向這個單鏈表頭。

當(dāng)需要申請內(nèi)存的時候,按照從小到大的順序,在這幾類里面找到剛好能夠容納下申請內(nèi)存的buf。如果找到,就直接將這類內(nèi)存塊的空閑鏈表頭返回給它即可。然后空閑鏈表頭指向next即可完成內(nèi)存的申請。

在釋放的時候,按照從大到小的順序,找到和待釋放的內(nèi)存塊大小相同的那類內(nèi)存塊,將其重新插入那類內(nèi)存塊空閑鏈表頭,即完成釋放。

這就是可變大小內(nèi)存池的分配基本思路。當(dāng)然我們這里舉例是只有大、中、小三類的內(nèi)存塊,實際可根據(jù)自己的需求增加,當(dāng)然可以更多大小不同的內(nèi)存塊。

2.2.1 初始化

在實現(xiàn)方面,由內(nèi)存低地址的內(nèi)存池描述結(jié)構(gòu)體poolDescriptor和跟在后面的pool buffer(數(shù)據(jù)實際存放位置)組成。一個poolDescripter數(shù)據(jù)項對應(yīng)一個pool buffer。

對于可變大小的內(nèi)存池分配,用戶在使用前,需要先配置內(nèi)存池描述結(jié)構(gòu)體。在大小上一般我們傾向于將其設(shè)置為4個字節(jié)的倍數(shù),方便單片機(jī)內(nèi)存32位對齊。然后由小變大的原則,16、32、64、280...。在數(shù)量上根據(jù)就需要根據(jù)自己的內(nèi)存使用量預(yù)估,找到合適的個數(shù)。

內(nèi)存池描述結(jié)構(gòu)體wsfBufPool_結(jié)構(gòu)如下:

/*! Buffer pool descriptor structure */ typedef struct {uint16_t len; /*! length of buffers in pool */uint8_t num; /*! number of buffers in pool */ } wsfBufPoolDesc_t;/* Internal buffer pool */ typedef struct {wsfBufPoolDesc_t desc; /* number of buffers and length */wsfBufMem_t *pStart; /* start of pool */wsfBufMem_t *pFree; /* first free buffer in pool */ } wsfBufPool_t;

如下所示,前面為每個內(nèi)存池buf大小(單位為word),后面為此大小的內(nèi)存池個數(shù)。一共定義是4個內(nèi)存此描述結(jié)構(gòu)體。即16個word的內(nèi)存有8個(16*4*8byte=512byte), 32個word的內(nèi)存有4個,64個word的內(nèi)存有6個,280個word的內(nèi)存有4個。

// Default pool descriptor. static wsfBufPoolDesc_t g_psPoolDescriptors[WSF_BUF_POOLS] = {{ 16, 8 },{ 32, 4 },{ 64, 6 },{ 280, 4 } };

在內(nèi)存初始化時,初始化函數(shù)就會讀取這個用戶自定義的內(nèi)存分配描述結(jié)構(gòu)體,初始化內(nèi)存池。

如上面設(shè)置了pool的個數(shù)為4個,依次初始化位于內(nèi)存低地址的內(nèi)存管理結(jié)構(gòu)體poolDescriptor:

跟著其后面的是buffer storage。buffer storage需要初始化為大小相同內(nèi)存塊,通過一個單向鏈表連接在一起,最后一塊內(nèi)存的*pNext指向NULL。*pStart會一直指向這個pool的頭地址,用于保存每個內(nèi)存池起始位置。*pFree會隨著alloc和free移動,保證始終指向空閑的內(nèi)存塊。

按照上面的結(jié)構(gòu)體,初始化后的整體內(nèi)存分布如下:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖2 內(nèi)存物理上總體分布圖

精簡后的初始化源代碼:

/*************************************************************************************************/ /*!* \fn WsfBufInit** \brief Initialize the buffer pool service. This function should only be called once* upon system initialization.** \param bufMemLen Length of free memory* \param pBufMem Free memory buffer for building buffer pools* \param numPools Number of buffer pools.* \param pDesc Array of buffer pool descriptors, one for each pool.** \return Amount of pBufMem used or 0 for failures.*/ /*************************************************************************************************/ uint16_t WsfBufInit(uint16_t bufMemLen, uint8_t *pBufMem, uint8_t numPools, wsfBufPoolDesc_t *pDesc) {wsfBufPool_t *pPool;wsfBufMem_t *pStart;uint16_t len;uint8_t i;wsfBufMem = (wsfBufMem_t *) pBufMem;pPool = (wsfBufPool_t *) wsfBufMem; //internal buffer management structure.在bufMem的最前面。 --yulong/* buffer storage starts after the pool structs */pStart = (wsfBufMem_t *) (pPool + numPools); //具體分派內(nèi)存的起始地址。wsfBufNumPools = numPools; //初始化pool數(shù)目4/* create each pool; see loop exit condition below */while (TRUE){/* exit loop after verification check */if (numPools-- == 0){break;}/* adjust pool lengths for minimum size and alignment。調(diào)整最小4字節(jié),以及對其 *///.....pPool->desc.num = pDesc->num;pDesc++; //遍歷入?yún)esc的每個內(nèi)存池描述DescpPool->pStart = pStart; //初始化起始地址和free地址pPool->pFree = pStart;/* initialize free list */len = pPool->desc.len / sizeof(wsfBufMem_t); // 4字節(jié)for (i = pPool->desc.num; i > 1; i--){/* pointer to the next free buffer is stored in the buffer itself */pStart->pNext = pStart + len;pStart += len;}/* last one in list points to NULL */pStart->pNext = NULL;pStart += len; //跳到這個內(nèi)存池的末尾/* next pool */pPool++;}wsfBufMemLen = (uint8_t *) pStart - (uint8_t *) wsfBufMem;WSF_TRACE_INFO1("Created buffer pools; using %u bytes", wsfBufMemLen);return wsfBufMemLen; }

2.2.2 分配原理

從內(nèi)存池描述結(jié)構(gòu)的頭開始,根據(jù)pPool->desc.len,按len從小往大的找。直到找到能夠容納下申請內(nèi)存大小的那個pool,然后將這個pool的pFree賦給pBuf,同時將pFree指向下一個空閑塊pNext。最后返回pBuf即完成內(nèi)存申請。核心代碼下面兩句:

/* allocation succeeded */ pBuf = pPool->pFree;/* next free buffer is stored inside current free buffer */ pPool->pFree = pBuf->pNext;

值得注意的是,雖然每個空閑內(nèi)存塊為了維護(hù)鏈表,前面都有一個*pNext指針和magic num(可選),但是當(dāng)分配給用戶后,由于其不再需要組織成一個鏈表,所以*pNext的值沒有任何意義,而magic num是free過后才賦值的。因此用戶在使用時,可以使用全部的內(nèi)存塊,不會為了維護(hù)鏈表,造成額外的空間浪費。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖3 內(nèi)存塊復(fù)用內(nèi)存空間

去掉輔助功能后的精簡代碼:

/*************************************************************************************************/ /*!* \fn WsfBufAlloc* \brief Allocate a buffer.* \param len Length of buffer to allocate.* \return Pointer to allocated buffer or NULL if allocation fails.*/ /*************************************************************************************************/ void *WsfBufAlloc(uint16_t len) {wsfBufPool_t *pPool;wsfBufMem_t *pBuf;uint8_t i;WSF_CS_INIT(cs); //線程保護(hù),準(zhǔn)備進(jìn)入臨界區(qū)pPool = (wsfBufPool_t *) wsfBufMem; // 獲得前面的內(nèi)存池描述結(jié)構(gòu)頭for (i = wsfBufNumPools; i > 0; i--, pPool++) //從小->大找pool池{/* if buffer is big enough */if (len <= pPool->desc.len) //如果找到了就分配,沒有找到找下一個更大的pool池{/* enter critical section */WSF_CS_ENTER(cs);/* if buffers available */if (pPool->pFree != NULL){/* allocation succeeded */pBuf = pPool->pFree;/* next free buffer is stored inside current free buffer */pPool->pFree = pBuf->pNext;/* exit critical section */WSF_CS_EXIT(cs);WSF_TRACE_ALLOC2("WsfBufAlloc len:%u pBuf:%08x", pPool->desc.len, pBuf);return pBuf;}/* exit critical section */WSF_CS_EXIT(cs);}}return NULL; }

2.2.3 釋放原理

需要釋放相應(yīng)的內(nèi)存塊,釋放時,直接將內(nèi)存塊重新加入空閑塊鏈表即可。由于有好幾種不同大小的內(nèi)存池,所以會先查找這個內(nèi)存塊屬于哪一個內(nèi)存池。釋放時會先初始化pPool為內(nèi)存最后(內(nèi)存最大)的那個內(nèi)存desc pool,從后向前找。當(dāng)pBuf>= pPool->pStart時,說明待釋放的內(nèi)存就在這個pool里面。所以執(zhí)行下面兩行即可:

/* pool found; put buffer back in free list */ // 注:*p為待free的內(nèi)存地址 p->pNext = pPool->pFree; pPool->pFree = p;

如果開啟了Free檢測,這會檢查magic num,避免被多次Free,造成錯誤。

精簡后的代碼如下:

/*************************************************************************************************/ /*!* \fn WsfBufFree* \brief Free a buffer.* \param pBuf Buffer to free.* \return None.*/ /*************************************************************************************************/ void WsfBufFree(void *pBuf) {wsfBufPool_t *pPool;wsfBufMem_t *p = pBuf;WSF_CS_INIT(cs);/* iterate over pools starting from last pool */pPool = (wsfBufPool_t *) wsfBufMem + (wsfBufNumPools - 1); // 從尾部desc倒著遍歷buf。while (pPool >= (wsfBufPool_t *) wsfBufMem){/* if the buffer memory is located inside this pool */if (p >= pPool->pStart){/* enter critical section */WSF_CS_ENTER(cs);/* pool found; put buffer back in free list */p->pNext = pPool->pFree;pPool->pFree = p;/* exit critical section */WSF_CS_EXIT(cs);WSF_TRACE_FREE2("WsfBufFree len:%u pBuf:%08x", pPool->desc.len, pBuf);return;}/* next pool */pPool--;}return; }

三、對比和總結(jié)

通過對比,可以看出這兩種內(nèi)存管理方式實現(xiàn)區(qū)別是:一種用位圖(這里用2個byte當(dāng)做一個位標(biāo)記),一種用鏈表。

這兩種分配方式各有優(yōu)缺點,在實際應(yīng)用時, 可根據(jù)需求作出相應(yīng)的選擇。如當(dāng)注重實時性和可靠性,而且申請內(nèi)存大小范圍已知可控,那我們可以選擇可變大小的內(nèi)存塊。當(dāng)注重靈活性時,可以選擇固定大小的內(nèi)存塊,雖然這會犧牲點效率。

當(dāng)然想要兼容這兩種,可以嘗試混合使用呀。比如:如果申請和內(nèi)存池大小接近的內(nèi)存就使用可變大小內(nèi)存池。而其他的較大的,或者較小的就在固定大小內(nèi)存池里去遍歷申請。

?優(yōu)點缺點
固定大小內(nèi)存塊1.靈活度高,能以較少的內(nèi)存碎片,分配各種大小的內(nèi)存;1.效率低,每次都要從尾部遍歷一遍memmap,找合適大小的內(nèi)存,置/清內(nèi)存表;
可變大小內(nèi)存塊1.申請和釋放速度快,效率高;

1.需提前估算大概的內(nèi)存需求大小;

2.靈活度不夠,分配不好很容易內(nèi)存碎片;

如有不妥之處,歡迎指正!謝謝

總結(jié)

以上是生活随笔為你收集整理的两种内存池管理方法对比的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。