分配模型概述
位图描述分配单元状态,连续扫描用于定位候选空间。
根据当前提供的实现说明,HRTOS 使用
OS_MEMORY
作为内存映射位图,并以连续空闲块搜索的方式为任务栈寻找空间。
每一位对应一个最小分配单元,位图状态反映该单元是否已经占用。
分配粒度:2 bytes
映射区域:OS_USER_RAM_INIT → OS_USER_RAM_EXIT
OS_MEMORY[x] bit = 1 // 已占用
OS_MEMORY[x] bit = 0 // 空闲
连续块搜索与任务创建
关注连续空闲单元,而不是只累计全部空闲空间。
按你提供的 os_task_create
逻辑描述,分配器扫描位图:遇到空闲位就累计连续长度;
遇到已占用位则清零。连续长度达到任务所需块数后,便可以确定候选区域。
k = 0;
for (i = 0; i < total_blocks; i++) {
if (bitmap[i] == 0) {
k++;
} else {
k = 0;
}
if (k >= required_blocks) {
/* 已找到满足连续长度的候选区域 */
/* 实际分配、标记与循环退出行为以源码为准 */
}
}
检查当前分配单元的状态。
空闲则递增,占用则重置计数。
检查连续块数量是否达到要求。
按实际实现记录地址并更新位图。
k 表示当前连续空闲单元计数;
required_blocks 对应所需连续块数量。
你给出的 sd 被描述为栈深度加一后的需求值,
但最终块数换算和边界条件仍应以真实分配代码为准。
栈空间映射与增长模型
分配位置由起始地址、索引与分配单元粒度共同决定。
i = OS_USER_RAM_INIT + (index * 2) + 1;
SP = i;
OS_INSIDE_STACK_USE_MAXIMUM = i + sd * 2;
这组表达式体现了按两字节粒度计算位置的思路。
index 决定分配单元在映射区中的偏移,
SP 由计算出的地址设置,
而 OS_INSIDE_STACK_USE_MAXIMUM
则根据栈需求计算另一个边界值。
为什么任务生命周期可能影响空间分布?
如果任务栈从一个连续区域中分配,任务创建与删除会改变位图中的占用分布。 当不同生命周期的任务交错创建和删除时,可能形成多个分离的空闲区间。 是否能再次利用这些区间,取决于删除时是否清除相应位图标记,以及后续搜索能否找到足够长的连续区域。
连续空间碎片如何形成
空闲空间可能仍然存在,但无法满足当前连续分配请求。
需要区分的三个指标
| 指标 | 含义 | 回答的问题 |
|---|---|---|
| 总空闲空间 | 所有空闲分配单元的总量 | 系统一共还剩多少空间? |
| 最长连续空闲区 | 最大的一段连续空闲单元 | 单次最多能申请多大的连续区域? |
| 当前请求大小 | 此次任务创建需要的连续空间 | 当前是否存在足够大的空闲区? |
碎片来源与实现边界
需要结合分配、删除与复用路径判断,而不是仅根据位图推断。
| 可能因素 | 对空间分布的影响 | 需要检查的实现 |
|---|---|---|
| 不同大小的栈请求 | 空闲区间长度可能不匹配后续请求。 | 栈深度换算与连续块搜索条件。 |
| 任务创建与删除交错 | 可能在仍有占用区域时形成分散空闲区。 | 删除路径是否释放对应位图单元。 |
| 任务生命周期不同 | 部分区域可能长期占用,其他区域反复申请和释放。 | 任务复用、删除和再次创建的完整流程。 |
| 高速任务与普通任务共用映射区 | 若确实共用同一分配区域,可能影响连续区间分布。 | 两类任务是否共享同一分配器与位图。 |
面向 8051 的内存规划策略
优先让资源需求可预估,再评估运行期间动态分配的必要性。
依据任务上限与系统可用内存核算总需求。
为每个任务选择合理的栈需求,避免无依据地扩大分配。
对生命周期固定的任务,可优先考虑启动阶段创建。
验证位图标记、释放范围和再次分配的行为。
建议重点验证的项目
- 申请失败时,位图和栈地址是否保持一致。
- 任务删除后,对应分配单元是否被正确释放。
- 连续空闲块的搜索起点、终止条件和边界是否正确。
- 不同栈深度请求能否复用已释放区域。
- 重复创建与删除任务后,内存映射是否出现残留占用。
关键结论
从位图状态进一步理解连续分配的可用性。
| 结论 | 准确含义 |
|---|---|
| 位图记录分配状态 | 通过各分配单元的标记,描述当前占用与空闲情况。 |
| 连续搜索影响分配结果 | 请求是否成功不仅取决于总空闲量,还取决于连续区间长度。 |
| 碎片不等于空间全部丢失 | 分散空闲区域仍可能被较小的后续请求复用。 |
| 释放机制决定可复用性 | 需要检查任务删除时的位图更新和后续分配行为。 |
| 静态规划降低运行期不确定性 | 合理的任务数量、栈深度与生命周期规划,有助于减少意外分配失败。 |