C语言动态内存分配原理以及堆区的使用(malloc、calloc、realloc、free)

C语言动态内存分配原理以及堆区的使用(malloc、calloc、realloc、free),第1张

C语言动态内存分配原理以及堆区的使用(malloc、calloc、realloc、free) C语言动态内存分配

文章目录

C语言动态内存分配

堆和栈动态内存调用释放的函数

malloccallocreallocfree 内存管理

内存泄漏动态内存分配原理(32bit *** 作系统为例)内存碎片什么时候使用动态内存

堆和栈

堆区 – 动态内存

手动申请使用,使用完之后,手动释放。 栈区 – 自动内存

程序允许时, *** 作系统自动分配。通常存放普通局部变量 函数调用 动态内存调用释放的函数

#include 

void *malloc(size_t size);
void *calloc(size_t nmemb,size_t size);
void *realloc(void *ptr, size_t size);
void free(void *ptr);
malloc

功能:申请动态内存

参数:向 *** 作系统申请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的动态内存块控制信息,内存的利用率不高容易造成内存碎片

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5714174.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存