动态内存分配
动态内存分配维护着一个进程的虚拟内存区域,称为堆(heap)。堆向上增长,用户栈向下生长。分配器将堆视作一组不同大小的块(block)的集合,有两种分配器。
显示分配器:malloc和free,new/delete,需要用户手动释放
隐式分配器:垃圾收集器,例如Java,不需要,自动释放
malloc实现
#include <stdlib.h> void *malloc(size_t size);
返回一个void* 指针,可以隐式转化为任意类型。其分配的块总是对齐的,32位操作系统是8的倍数,64位下是16的倍数。
malloc并不初始化其分配的内存,calloc初始化。在使用的时候需要注意。
free实现
#include <stdlib.h> void free(void *ptr)
malloc和free成对出现
分配器的要求和目标
1. 处理任意请求的序列
2. 立即响应请求
3. 只使用堆,为了使分配器可扩展
4. 对齐块
5. 不修改已分配的块
碎片:当虽然有未使用的内存但不能用来满足分配请求时,就会产生碎片。碎片会造成堆的利用率较低
C程序中常见的与内存相关的错误
1. 间接引用坏指针
常见示例scanf错误。
// 正确 scanf("%d", &val); // 错误 scanf("%d", val);
2. 读未初始化的内存
如malloc分配内存后,没有将分配内容清零
3. 允许栈缓冲区溢出
4. 假设指针和它们指向的对象时相同大小的
5. 数组越界、内存泄露(成对出现)
6. 引用不存在的变量
7. 引用空闲堆块中的数据