C/C++语言通过动态链表实现按需内存分配和使用(Linux Ubuntu 24.04环境)

我认为比较理想的内存使用方式应该实现这几个特性:

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 blocks
  int blocks_used;     // sum of used bytes of blocks
  int 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qiuzen

您的资助将帮助我创作更好的作品

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值