首先,由于堆内存无法与变量名建立映射关系,所以对堆内存必须配合指针使用。
C语言中,并没有与堆内存相关的关键词或者语句,而是由标准库提供了一套管理堆内存的函数供我们使用,位于stdlib.h之中。
分配堆内存
//Description: 向系统申请一块堆内存。
//size: 内存块的字节数。
//return: 成功返回内存块首地址;失败返回NULL。
void *malloc(size_t size);
1、首次使用malloc申请内存时,malloc会向操作系统申请内存,操作系统会一次性分配33页(每页4096字节)的内存供malloc管理,
之后再使用malloc申请内存,就会从这33页内存中进行分配。
2、malloc分配的内存块之间有一些空隙(4~12字节),这些空隙中存在一个指针,这个指针所指向的空间记录了malloc的管理信息,
一旦破坏就会产生错误。
3、使用malloc申请的内存,里面的数据是随机的、不确定的。如果需要对内存进行初始化可以使用以下bzero()和memset()函数。
//Description: 按块分配堆内存
//nmemb: 要申请的块数
//size: 每块的字节数
//return: 申请到的内存块的首地址
void *calloc(size_t nmemb, size_t size);
1、该函数底层调用的是malloc,分配的是一整块内存,nmenb和size参数只是提高了代码的可读性,调换实参不影响最后的结果。
2、calloc会把分配的内存初始化为0,所以速度比malloc慢。
//Description: 调整已经申请到的内存块的大小,可以往大调整,也可以往小调整
//ptr: 申请到的内存块首地址
//size: 要调整的目标字节数
//return: 调整后的内存块首地址
void *realloc(void *ptr, sizre_t size);
1、如果再原块的基础上无法调整,realloc会重新申请一块size个字节的内存,把原ptr的内容拷贝过去,再把ptr释放。
释放堆内存
//Description: 释放内存
//ptr: 要释放的内存首地址
//return: void
void free(void *ptr);
1、free()可以释放空指针。
2、不可以重复释放同一块内存。
3、只释放使用权,但不会清理被释放的内存。
4、主要遵循两个原则:
4.1、谁申请谁释放
4.2、谁知道该释放,谁释放
总结
1、操作系统对堆内存的管理决定了是否产生段错误,而malloc、free只是在管理堆内存的使用权限,
如果越界访问堆内存,可能会影响malloc和free的后续使用,也可能产生脏数据。
2、堆内存与栈内存的区别:主要是大小、使用方式、安全性的区别。
栈内存:容量小,由系统自动管理,安全性高。
堆内存:容量大,由程序员手动管理,容易造成内存泄露,内存碎片。