range-alloc-arceos 技术文档
路径:
components/range-alloc-arceos类型:库 crate 分层:组件层 / 区间分配算法组件 版本:0.1.4文档依据:当前仓库源码、Cargo.toml、README.md、src/lib.rs、tests/test.rs、components/axdevice/src/device.rs、components/axvm/src/vm.rs、os/axvisor/src/vmm/hvc.rs
range-alloc-arceos 的真实定位是一个泛型连续区间分配器。它管理的是一个初始范围上的“哪些子区间空闲、哪些子区间已占用”,并提供 best-fit 分配与回收合并逻辑。它不是页分配器,不处理地址映射,不理解设备,不负责对齐策略,更不是完整的内存管理子系统。
1. 架构设计分析
1.1 设计定位
这个 crate 的问题模型非常明确:
- 有一个初始区间
start..end - 需要不断从中分配连续子区间
- 需要在释放时把相邻空闲区间重新合并
- 希望尽量降低碎片化
因此它选择的核心数据结构不是树或位图,而是:
- 一个有序的
Vec<Range<T>> free_ranges
并把已分配区间看作“初始区间减去空闲区间”的补集。
1.2 核心数据结构
RangeAllocator<T> 内部只有两项状态:
| 字段 | 作用 |
|---|---|
initial_range | 整个分配器负责管理的总范围 |
free_ranges | 当前空闲区间表,按起始地址升序排列且互不重叠 |
这两个不变量非常关键:
free_ranges必须有序free_ranges之间不能重叠
几乎所有接口都围绕维护这两个不变量展开。
1.3 分配策略:best-fit
allocate_range(length) 的实现会遍历所有空闲区间,并选择:
- 能满足请求的最小空闲区间
这是一种典型的 best-fit 策略。它的好处是:
- 优先消耗最贴合请求的空闲块
- 尽量保留大块连续空间
若找不到足够大的单个区间,则返回:
RangeAllocationError { fragmented_free_length }
其中 fragmented_free_length 表示把所有空闲区间长度加起来后,总共还有多少空闲量。这个字段能帮助调用者区分:
- 是真的没空间了
- 还是只是碎片太多,凑不出连续区间
1.4 回收策略:邻接合并
free_range(range) 的逻辑重点不在简单插入,而在合并:
- 如果与左邻接,则与左合并
- 如果与右邻接,则与右合并
- 如果左右都邻接,则把三段合成一段
- 否则在有序位置插入
源码中还有断言确保:
- 释放区间必须位于
initial_range内 - 区间必须非空
- 插入后不会与现有空闲区间重叠
这意味着:
- 双重释放或越界释放不是被“静默忽略”,而是会触发断言
1.5 扩容与观察接口
除了分配/回收,这个 crate 还提供了几个非常实用的辅助接口:
grow_to(new_end):扩展管理上界allocated_ranges():通 过空闲表反推出当前已分配区间reset():恢复到初始全空闲状态is_empty():检查是否尚未分配任何区间total_available():统计所有空闲区间的总长度
尤其是 allocated_ranges(),说明这个分配器不仅能“给空间”,也适合做状态观察和调试。
1.6 与 Axvisor 当前实现的真实关系
当前仓库里的真实调用链非常清晰:
axdevice::AxVmDevices在IVCChannel设备配置初始化时,创建RangeAllocator<usize>- 这个区间的范围来自 IVC 共享内存的 guest physical address 空间
axvm::VM::alloc_ivc_channel()先把请求大小向上对齐到 4K- 然后调用
devices.alloc_ivc_channel(),最终落到RangeAllocator::allocate_range() os/axvisor/src/vmm/hvc.rs在处理 IVC hypercall 时使用这套分配/回收能力
这条链路很重要,因为它清楚地说明了:
- 对齐是
axvm做的,不是本 crate 做的 - 地址映射是
axdevice/axvm/axvisor做的,不是本 crate 做的 - 本 crate 只是区间分配算法核心