面试题答案
一键面试内存碎片化问题描述
在大型C语言项目大量动态内存分配与释放操作中,内存碎片化会出现。分为内部碎片化和外部碎片化。
- 内部碎片化:当分配的内存块大于实际所需内存时,多分配的那部分内存就形成了内部碎片,无法被其他请求使用。例如
malloc(100)
,实际只用50字节,剩下50字节就浪费了。 - 外部碎片化:不断地分配和释放内存后,内存空间会出现许多小块空闲区域,但这些小块由于不连续,无法满足较大内存分配请求。比如系统中有10个10字节空闲块,但需要分配100字节连续空间时,就会因外部碎片化导致分配失败。
优化内存管理减少碎片化策略
- 内存池策略
- 实现思路:预先分配一块较大的内存作为内存池,当有内存分配请求时,从内存池中分配小块内存。当释放内存时,将其归还给内存池,而不是直接归还给操作系统。例如可以通过链表结构来管理内存池中的空闲块,每个节点代表一个空闲块,节点中记录块的大小和指向下一个空闲块的指针。分配内存时,遍历链表找到合适大小的块,并从链表中移除;释放内存时,将其插入链表合适位置。
- 潜在风险:内存池大小不好确定。如果设置过小,不能满足所有分配需求,仍需向系统申请内存,可能导致碎片化;如果设置过大,会浪费大量内存。另外,如果分配和释放的内存块大小差异很大,可能在内存池中也会形成类似外部碎片化的情况。
- 按大小分类管理策略
- 实现思路:根据内存请求大小范围,将内存分配请求分为不同类别,每个类别有自己独立的内存管理机制。比如将请求分为小(1 - 100字节)、中(101 - 1000字节)、大(1001字节以上)三类。分别为每类请求维护一个空闲链表,链表节点包含空闲块指针和大小等信息。分配内存时,根据请求大小选择对应的链表查找合适空闲块;释放内存时,根据大小插入相应链表。这样不同大小的请求互不干扰,减少碎片化。
- 潜在风险:增加了管理复杂度,需要维护多个链表。并且如果类别划分不合理,会导致某一类别链表中仍出现碎片化问题,例如类别划分过粗,不同大小请求都集中在某一类,仍可能造成类似普通管理方式下的碎片化。同时,可能存在某个类别链表空闲块过多,而其他类别链表空闲块不足的情况,导致整体内存利用率不高。