标记-整理算法是应对外部碎片最直接有效的手段,通过标记存活对象、向一端紧凑迁移、更新所有引用三步,腾出连续空闲空间,兼顾回收与规整,适合长期运行的高压力场景。

标记-整理算法是应对内存碎片,尤其是外部碎片最直接有效的手段之一。它不回避碎片,而是主动腾挪、重排已分配内存,把零散空闲空间聚合成连续大块,从而恢复大内存请求的满足能力。
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
标记-整理的核心逻辑是“先清点、再搬家、最后归位”
它不是简单地回收空闲块,而是在保留所有活跃数据的前提下,压缩整个堆空间。整个过程分三步走:
- 标记阶段:遍历所有对象或内存块,识别哪些仍在使用(即“存活”),哪些可被回收;
- 整理阶段:将所有存活块按顺序紧凑迁移,通常从低地址向高地址排列,空出高地址的大片连续空闲区;
- 更新与重建:同步修正所有指向原地址的指针(或句柄/引用),并刷新空闲链表或位图,使系统感知到新的可用布局。
为什么它比标记-清除更实用?
标记-清除只回收不移动,容易留下大量小空闲块,久而久之导致外部碎片堆积,最终分配失败。而标记-整理在回收的同时完成空间规整,一次操作兼顾清理与优化,特别适合长期运行、内存压力渐增的场景,比如JVM的G1和ZGC中的部分混合回收,以及Redis重启后加载RDB时的内存重排。
实施中必须注意的关键细节
- 指针更新不能遗漏:C/C++等手动管理语言中,若存在原始指针直接指向对象,移动后未更新就会造成悬垂指针,引发崩溃;推荐用句柄层或虚拟内存映射来解耦逻辑地址与物理位置。
- 移动顺序要自高向低复制:避免新旧数据区域重叠覆盖,尤其在单块内存内整理时,从高地址开始拷贝更安全。
- 整理不是越勤越好:每次整理涉及大量内存拷贝和引用更新,开销显著;应设定触发条件,例如空闲块数量超阈值、最大空闲块小于某值、或最近N次分配失败中有M次因碎片导致。
它不是万能的,但却是可控的底线方案
标记-整理无法消除内部碎片(比如固定页大小带来的浪费),也不能替代良好设计——像内存池、Slab分配器、对象复用这些预防性策略,始终比事后整理更高效。但它为那些无法提前预判内存模式、又不能接受频繁OOM的系统,提供了一条确定可靠的兜底路径。

















