我認為比較理想的內存使用方式應該實現這幾個特性:
1. 分配一塊能滿足大多數情況下需求的內存,比如80%的情況下都不需要再次分配內存。
2. 對另外20%需要較多內存的情況,可以通過動態鏈表按需追加新的內存塊。
3. 要對總共消耗的內存有一個最大數量限制,比如200M。
下面就是一個比較理想的通過動態鏈表實現按需內存分配和使用的例子,取名MemChain
#define BudaMc(size) (char*)alloc(size)
#define BudaM(T) (T*)alloc(sizeof(T))
#define BudaMn(T, name) T *name = (T*)alloc(sizeof(T))
#define BudaZ(T, name) T name; memset(&name, 0, sizeof(name))
#define BudaFree(m) if(m){ free(m); m = NULL; }
#define BudaMax(a, b) ((a)<(b)?(b):(a))typedef struct mem_chain_block
{char *mem;struct mem_chain_block *next;int size;int used;
} MemChainBlock;
typedef struct mem_chain
{struct mem_chain_block *first;struct mem_chain_block *last;int max_size;int used; // sum of allocated mem of blocksint blocks_used; // sum of used bytes of blocksint block_min_size;int block_count;
} MemChain;// calloc memory, log fail message
void* alloc(int size);
// MUST use free_mem_chain to free heap mem used
MemChain* create_mem_chain(int max_size=100002048, int block_min_size=2048);
// destroy the whole mem_chain
void free_mem_chain(MemChain *mc);
// delete all the blocks except the first one, reset mem_chain to the beginning
void reset_mem_chain(MemChain *mc);
// return NULL if failed
MemChainBlock* mem_chain_add_block(MemChain *mc, int size);
// If the memory size to use is known to be size, use this function; otherwise, use the next function.
// Return NULL if failed, return the start of used memory if succeed.
char* use_mem_chain(MemChain *mc, int size, char* content=NULL);
// Return NULL if failed, return the start of used memory if succeed.
char* use_mem_chain(MemChain *mc, const char* format, ...);namespace BUDA
{void* alloc(int size){if (size <= 0) { log("alloc size cannot be less than 1\n"); return NULL; }void* r = calloc(1, size); if (!r) { log("alloc %d bytes memory failed.\n", size); return NULL; } return r;}MemChain* create_mem_chain(int max_size, int block_min_size){log("create_mem_chain %d/%d", max_size, block_min_size);BudaMn(MemChain, mc); BudaMn(MemChainBlock, mcb); if(mc==NULL || mcb == NULL) return NULL;mcb->mem=BudaMc(block_min_size); if(mcb->mem == NULL) return NULL; mcb->size=block_min_size; mc->max_size=max_size; mc->used+=mcb->size; mc->block_min_size=block_min_size; mc->first=mc->last=mcb; mc->block_count=1;return mc;} MemChainBlock* mem_chain_add_block(MemChain *mc, int size){log("mem_chain_add_block %d", size);if(size+mc->used > mc->max_size) { log("mem_chain reached max_size: %d", mc->max_size); return NULL; }BudaMn(MemChainBlock, mcb); if(mcb == NULL) return NULL;mcb->mem=BudaMc(size); if(mcb->mem == NULL) return NULL; mcb->size=size; mc->used+=size; mc->block_count++; mc->last->next=mcb; mc->last=mcb;return mcb;}void free_mem_chain(MemChain *mc){log("free_mem_chain %d", mc->used);int remain_block_count = mc->block_count; MemChainBlock *mcb=mc->first, *next; BudaFree(mc);while(mcb) { next=mcb->next; BudaFree(mcb->mem); BudaFree(mcb); remain_block_count--; mcb=next; }if(remain_block_count) { log("MemChain block_count broken: %d", remain_block_count); }}void reset_mem_chain(MemChain *mc){log("reset_mem_chain %d/%d", mc->max_size, mc->block_min_size);MemChainBlock *first=mc->first; MemChainBlock *mcb=first->next, *next; while(mcb) { next=mcb->next; BudaFree(mcb->mem); BudaFree(mcb); mcb=next; }mc->block_count=1; mc->blocks_used=0; mc->last=first; mc->used=first->size;first->next=NULL; first->used=0;}char* use_mem_chain(MemChain *mc, int size, char* content){log("use_mem_chain %d bytes", size);MemChainBlock *last=mc->last;if(last->used + size > last->size){int asize=BudaMax(mc->block_min_size, size); last = mem_chain_add_block(mc, asize); if(last==NULL) return NULL;}char* write_start=last->mem + last->used; last->used += size; mc->blocks_used+=size;if(content) memcpy(write_start, content, size);return write_start;}char* use_mem_chain(MemChain *mc, const char* format, ...){//log("try use_mem_chain : %s", format);MemChainBlock *last=mc->last; int used=last->used; char *write_start=last->mem+used; int remain=last->size - used, len, asize=mc->block_min_size;write: va_list args; va_start(args, format); len = vsnprintf2(last->mem + used, remain, format, args); va_end(args);if(len == -1) {last = mem_chain_add_block(mc, asize); if(last==NULL) return NULL; used=0; write_start=last->mem; remain=asize; asize*=2; goto write;}else{last->used += len; mc->blocks_used+=len;log("use_mem_chain %d bytes : \n%s", len, write_start);}return write_start;}}
作者寄語
以上如有錯漏之處,敬請大家指正。我是主修C/C++、Vue3,開發網站的程序員,我的聯系方式:
微信:TobeBuda
Email/Paypal: jinmin.si@outlook.com
邀請您加入「社區資訊服務」創業微信群,共同探討打造社區資訊服務的美好未來。
參考資料
chatgpt
gemini
mistral
claude