您现在的位置是:亿华云 > 系统运维
C语言动态内存分配
亿华云2025-10-09 01:34:21【系统运维】0人已围观
简介前言首先要明白为何需要动态内存分配,熟悉C语言的读者应该对这个比较熟悉,需要一段内存时会使用malloc函数来申请所需要大小的内存,函数返回一段内存的首地址。简单来说,动态内存分配的好处在于需要内存的
前言
首先要明白为何需要动态内存分配,语言动熟悉C语言的态内读者应该对这个比较熟悉,需要一段内存时会使用malloc函数来申请所需要大小的存分内存,函数返回一段内存的语言动首地址。简单来说,态内动态内存分配的存分好处在于需要内存的时候可以按需分配,当不需要内存的语言动时候可以将其释放掉,这样可以高效的态内利用内存。下面本文从零开始实现一个完整的存分动态内存分配。
简单动态内存分配实现
内存分配是语言动将没有使用的内存块给需要的变量(普通变量、指针变量、态内结构体变量等等)使用,存分由于其使用后需要进行释放,语言动这就会导致空闲的态内内存是分散在内存池中的。因此,存分必须要对内存进行管理,也就是对内存的使用情况做标记。
上图是企商汇一个内存池使用后的某一时刻,可以看到,使用的块和没有使用的块并不是连续的,这样就需要用一个表对其进行标记,这个表称为BitMap。假设现在将内存按照每个Byte进行划分,然后用一个bit对块进行标记,1表示已使用,0表示没有使用,这样一个块需要一个bit。
下面来用C语言来实现这个简单的动态内存分配。
#include <stdio.h> #define MEM_POOL_SIZE 64 unsigned char MemPool[MEM_POOL_SIZE]; unsigned char BitMap[MEM_POOL_SIZE/8]={ 0}; //BitMap[0] MSB->LSB MemPool[0 ~ 8] //BitMap[1] MSB->LSB MemPool[9 ~15] //BitMap[2] MSB->LSB MemPool[16~23] // ... void InitMemAlloc(void) { int i=MEM_POOL_SIZE; while(i--) { MemPool[i]=0; } i=MEM_POOL_SIZE/8; while(i--) { BitMap[i]=0; } } void *MemAlloc(unsigned int m_size) { unsigned int i=0,j=0,k=0,index=0,count=0,mapv=0,cache; if(m_size>MEM_POOL_SIZE) { return NULL; } else { for(;i<MEM_POOL_SIZE/8;i++) { mapv=BitMap[i]; //取出高位 for(j=0;j<8;j++) { cache=(mapv&0x80); if(cache==0) { count++; if(count==m_size) { for(;k<m_size;k++) { BitMap[(index+k)/8]|=(1<<(7-((index+k)%8))); } return &MemPool[index]; } } else { count=0; iindex=i*8+j+1; } mapv<<=1; } } return NULL; } } void MemFree(void *p,unsigned int m_size) { unsigned int k=0,index=(((unsigned int)p)-(unsigned int)MemPool); for(;k<m_size;k++) { BitMap[(index+k)/8]&=~(1<<(7-((index+k)%8))); } } void MemPrintBitMap(void) { unsigned int i,j,value; for(i=0;i<MEM_POOL_SIZE/8;i++) { value=BitMap[i]; for(j=0;j<8;j++) { if(value&0x80) printf("1 "); else printf("0 "); value<<=1; } printf("\n"); } } double MemGetUsedPercent(void) { unsigned int i,j,value; double ret=0.0; for(i=0;i<MEM_POOL_SIZE/8;i++) { value=BitMap[i]; for(j=0;j<8;j++) { if(value&0x80) ret++; value<<=1; } } return (ret*100)/MEM_POOL_SIZE; } int main(int argc, char **argv) { int *p=MemAlloc(10); printf("The pool is used=%f\n",MemGetUsedPercent()); MemPrintBitMap(); int *q=MemAlloc(5); printf("The pool is used=%f\n",MemGetUsedPercent()); MemPrintBitMap(); MemFree(p,5); printf("The pool is used=%f\n",MemGetUsedPercent()); MemPrintBitMap(); return 0; }最终终端输出结果如下:
上面已经实现了一个简单的动态内存分配,可以完成内存的分配和释放以及输出使用率和查看位图。这种方式实现的动态内存分配不会产生内部碎片,这也是其优势所在,但其缺点很明显就是利用率太低。
实用的动态内存分配
细心的读者可能已经发现上面的简单动态内存分配有一个缺点,就是一个bit只能表示一个字节,云南idc服务商也就是说表示8个字节就需要一个字节的位图,这种映射导致其内存的
这对于很多情况是比较浪费的。为了提高利用率,就必须将映射块的粒度增大,也就是一个Bit的映射范围对应多个字节。
上图给出了一个bit映射到64Byte,这样:
虽然利用率变高了,但是其会产生内部碎片,所谓内部碎片就是在最小粒度内无法使用的内存空间,为何这个空间无法使用了,原因在于当在申请内存块的时候,其内存只能以64B对齐的,即使小于64B,也得按64B来看作,因为这个粒度已经被bitmap标记使用了,当下次使用时,其无法被分配。因此,可以看到,粒度越大,服务器托管其可能产生的内部内存碎片越大,内存利用率和碎片是需要权衡了,好的算法只能解决外部碎片问题,无法解决内部碎片问题,因此在实现动态内存分配时必须权衡考虑,以达到最优结果。
很赞哦!(98391)
相关文章
- 网站页面结构改版,仅是页面样式发生变化,不会对排名、收录有影响;只有涉及到页面URL改变,才会对网站排名、收录有影响。
- 调查显示开发者讨厌PHP,喜爱Python
- 漫话:如何给女朋友解释乐观锁与悲观锁?
- 网友编写出《流浪地球》“春节十二响”C语言源码
- 2、根据用户基础选择访问提供程序。由于互联问题的存在,接入商的选择也非常重要,如果用户群主要在联通,尽量选择联通接入较好的接入商,如果用户群主要在电信,那么选择电信接入较好的接入商。如果用户组位于国家/地区,则选择更好的访问提供程序进行交互。
- 基于数据驱动的酒店对账自动化测试系统
- 2018 Python官方年度报告:关于 Python 的趋势都在这了
- Puppet自动化集群管理基础篇
- 比较五款企业级ETL工具,助你选出适合项目的解决方案