内存碎片
内存碎片是指堆中可用的空闲内存被分割成许多小块,虽然总空闲内存足够,但无法满足较大的分配请求。内存碎片分为外部碎片(空闲块分散)和内部碎片(分配块大于请求大小)。
外部碎片
分配 100 字节 → 分配 200 字节 → 释放 100 字节 → 分配 150 字节
[已分配 100][空闲 100][已分配 200]
↑
释放 100 字节后
[空闲 100][已分配 200][空闲 100]
/* 请求 150 字节失败:没有连续 150 字节的块 */
内部碎片
/* 分配器按 8 字节对齐 */
void *p = malloc(5); /* 实际分配 8 字节,浪费 3 字节 */
减少碎片策略
固定大小分配:
/* 只分配 16, 32, 64, 128... 等固定大小 */
void *alloc_16(void) { /* 从 16 字节池分配 */ }
void *alloc_32(void) { /* 从 32 字节池分配 */ }
内存池:
/* 同生命周期对象一起分配、一起释放 */
struct Pool pool;
/* 分配多个对象 */
pool_reset(&pool); /* 一次性释放,无碎片 */
紧凑分配:
/* 先分配大对象,再分配小对象 */
void *large = malloc(10000);
void *small1 = malloc(100);
void *small2 = malloc(100);
/* 释放大对象后,小对象不会阻止大块重用 */
碎片度量
/* 简单度量:最大连续空闲块 / 总空闲内存 */
/* 比值越小,碎片越严重 */
最佳实践
- 固定大小对象用内存池
- 同生命周期对象一起分配释放
- 避免频繁分配释放不同大小对象
- 长时间运行程序定期整理或重启
- 实时系统预分配所有内存