C语言动态内存分配
堆和栈动态内存调用释放的函数
malloccallocreallocfree 内存管理
内存泄漏动态内存分配原理(32bit *** 作系统为例)内存碎片什么时候使用动态内存
堆和栈堆区 – 动态内存
手动申请使用,使用完之后,手动释放。 栈区 – 自动内存
程序允许时, *** 作系统自动分配。通常存放普通局部变量 函数调用 动态内存调用释放的函数
#includemallocvoid *malloc(size_t size); void *calloc(size_t nmemb,size_t size); void *realloc(void *ptr, size_t size); void free(void *ptr);
功能:申请动态内存
参数:向 *** 作系统申请size字节的动态内存 //size是以字节为单位
返回值类型:void *
万能指针(指向内存地址) *** 作系统储存内存必须知道内存的类型以分配内存大小,void*为了处理各种类型的变量,表示动态内存的起始位置。所以我们在使用动态内存的时候需要将void* 转化为具体的类型。
返回结果:
失败:返回NULL成功:返回size个字节的内存的开始位置
使用步骤:
申请动态内存
申请字符串,需要用到strcpy函数等对内存进行 *** 作的函数。
可以申请数组
//一维数组 int *pa = (int *)malloc(15*sizeof(int)); //== arr[15] //二维数组 和函数参数的声明类似 int (*pb)[3] = (int *)malloc(15*sizeof(int));// ==brr[5][3] int (*px)[5] = (int (*)[5])pb; //可以直接强制转化成 xrr[3][5] free(px) // px ,pb ,pa指向同一块动态内存 只用free一次就行了。
判断是否成功
#include#include // malloc 以及其他内存分配的函数基本输都在此头文件 int main(){ void *ptd = malloc(4); if(ptd == NULL){ printf("malloc failed!n"); exit(EXIT_FAILURE); //成功exit(EXIT_SUCCESS) } int * ptr = (int *)ptd; }
转化为具体类型的指针
使用动态内存
释放动态内存
calloc申请动态内存
void *calloc (size_t nmemb, size_t size);相当于 malloc(nmemb*size) 官方手册中calloc和malloc的区别
malloc对申请的动态内存不会进行擦除,即原内存不会清零然而calloc申请到的一定进行过擦除 ,内存申请到的全部为0其余基本上都一样。 realloc
void *realloc(void *ptr, size_t size);
功能:调整动态内存大小
参数:调节的必须是malloc/calloc/realloc的返回值
返回值:
success:调整后的动态内存的首地址fail:NULL
realloc的底层实现:
如果该内存空间后面有足够size给字节可供调节,则地址不变如果后面的内存空间不够,那就会重新分配地址并把数据一并拷贝,原来的内存将被自动释放。
注意事项:
一般一定要重新接收返回值。 free
void free(void *ptr);功能:释放内存注意:
不要多次释放不要忘了释放(忘记释放会造成内存泄漏) 内存管理 内存泄漏
动态内存忘记释放;延迟(时间比较久)释放,都可称为内存泄漏。造成原因:
忘记释放释放动态内存的代码没有被执行到 内存泄漏的检测
valgrindgdb 内存泄露的问题:
程序运行时间越长,占用的内存越多,最后可能导致内存耗尽,导致程序崩溃。 动态内存分配原理(32bit *** 作系统为例)
在程序中,第一次申请动态内存,malloc至少分配33页的内存
1页 = 4096Byte = 4KBls
#include//不是标准C语言头文件 而是linux *** 作系统文件 windows下也有对应的 int getpagesize(void); //获得一页内存的大小 字节数 4096Byte(字节) = 4KB
int main(){ char *s = malloc(1); //申请1byte int i; //打印了33页的数据 for(i=-8;i<33*4096-8;i++){//[s-8,s+33*4096-8) 这片内存打印 printf("%x ",s[i]); } printf("n"); free(s); }
即使所有的动态内存都free,最开始分配的33页动态内存一定会被保留
32bit处理器下,申请的动态内存自动以4字节对齐,即使申请1个字节,但其实也有8byte的空间
对于每一块动态内存,都有额外的一块空间用于保存该动态内存块的信息,一般是8-12byte
把这8-12byte称为动态内存块控制信息 (是否空闲,大小,下一个动态内存块)动态内存块控制信息一旦修改,在free时基本上都会导致程序崩溃
每两块动态内存之间,至少相隔16byte(64bit处理器 32byte) 至少8byte的动态内存控制块信息 至少4byte的数据(malloc给用户的空间, 4byte缓冲 realloc只是增加4字节,并会不使用新的内存)
使用动态内存,遵循申请几个字节,使用几个字节的原则,不要越界访问
如果越界访问,可能导致各种问题
如果在申请动态内存中,之前分配的33页没有用完之前,后续的malloc都是在33页内存里划分一块动态内存
如果最初的33页使用完了,后续分配是以页为单位 如果发现不够,则映射一页内存,如果发现有内存页存在空闲,则回收页内存
申请动态内存的过程
如果第一次申请 分配33页的动态内存 然后划出一块内存(以及8字节动态内存块) 返回用户一块可以使用的内存(一般都在控制信息块后面)如果不是第一次,则从已经动态内存块中查找空闲(被free)动态内存块且大小合适(动态内存块的大小不小于用户申请内存的大小)的内存块返回给用户,且设置为忙碌(非空闲状态)如果目前没有合适的,则从后面的动态内存中划分一块合适的内存如果后面内存不足,则进行页映射(分配新的一页)如果在free过程中,发现多块动态内存处于空闲状态,则合并动态内存块如果发现页空闲(除最开始33页外),则回收页(取消页映射)以上的目的是为了提高分配申请的效率 内存碎片
动态内存在不断地申请和释放的过程中,导致内存块之间的一些内存永远也无法被使用到,称为内存碎片如何减少内存碎片,小内存使用栈,大内存使用堆 及时释放没必要的动态内存在重复申请和释放的过程中,有一些大的内存块分配给小于该内存块字节数据的用户申请使用,导致部分内存无法被使用,----内存碎片为什么小块内存不要用堆内存
分配耗时每一块动态内存都需要额外至少8byte的动态内存块控制信息,内存的利用率不高容易造成内存碎片 什么时候使用动态内存
不清楚需要使用多少内存,动态变化的内存 栈内存大小是固定的
内存比较大时 小内存建议使用栈
项目中,存储数据往往都是使用动态内存
用,----内存碎片
为什么小块内存不要用堆内存
分配耗时每一块动态内存都需要额外至少8byte的动态内存块控制信息,内存的利用率不高容易造成内存碎片
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)