2. VxWorks内存管理架构总览

VxWorks 的内存管理并不是“一个 malloc 函数”那么简单,它由硬件内存管理单元(MMU)、内核内存分配器、区域(region/partition)划分机制以及任务上下文共同构成。理解这套架构的关键,是先分清“谁在管内存”“内存被切成什么”“内核和用户空间如何隔离”,最后才能谈实时性约束下该如何取舍。

一、MMU 在 VxWorks 中扮演什么角色

VxWorks 支持两种典型构建形态:无 MMU 的 UP/AMP 配置与带 MMU 的 RTP(Real-Time Process)配置。在无 MMU 时,所有任务共享同一个物理地址空间,虚拟地址等于物理地址,访问速度快、确定性高,但一个野指针就可能踩坏内核数据。带 MMU 时,MMU 负责虚拟地址到物理地址的转换,并提供页级保护属性(可读、可写、可执行、缓存策略)。

MMU 的核心作用有三点:地址翻译、访问权限检查、缓存属性控制。VxWorks 通过页表把地址空间划分为内核空间与用户空间,用户态 RTP 只能访问映射给自己的页,越界访问会触发异常而不是静默破坏内核。代价是每次地址翻译增加 TLB 查找开销,缺页和 TLB miss 会引入不确定性,这正是实时性设计中必须权衡的地方。

二、内存区域划分:从物理内存到可用池

系统启动时,VxWorks 首先识别物理内存布局,把内存划分为若干区域。典型划分包括:

  • 内核映像区:存放 vxWorks 映像、只读代码段与初始化数据,通常映射为只读+可执行。
  • 系统内存池(system memory pool):内核与驱动动态分配的主要来源,由 memPartLib 管理。
  • RTP 用户空间:每个 RTP 拥有独立虚拟地址空间,其堆由用户态分配器管理。
  • 共享内存区:用于 RTP 之间或核间通信,需显式映射并约定同步方式。
  • 保留区:给 DMA、外设寄存器或 bootrom 预留,避免被分配器占用。

这些区域不是自动最优的,需要根据目标板内存大小、DMA 缓冲需求、RTP 数量手工规划。例如一块 512 MB DDR 的板卡,可能保留 64 MB 给 DMA 一致性缓冲,其余交给系统池和 RTP 堆。

VxWorks 内存管理架构总览 物理内存 内核映像区 只读 + 可执行 系统内存池 memPartLib 管理 DMA 保留区 一致性缓冲 共享内存区 RTP / 核间通信 RTP 用户空间 独立虚拟地址 MMU 地址翻译 权限检查 缓存属性 页表 / TLB 内核空间 任务 / 驱动 / ISR 直接访问系统池 无页保护开销 确定性高 风险:野指针破坏全局 用户空间(RTP) 独立虚拟地址空间 页级隔离保护 缺页 / TLB 开销 崩溃不影响内核 适合非关键业务 实时性约束:确定性 > 隔离性 > 内存利用率 —— 关键路径避免缺页与动态分配

三、内核空间与用户空间的边界

在带 MMU 的配置中,内核空间通常占据虚拟地址的高半区,用户 RTP 占据低半区。内核任务运行在特权模式,可以直接访问系统内存池;RTP 运行在非特权模式,只能访问映射到自己的页。两者之间的数据交换必须通过系统调用或共享内存完成。

这种隔离带来两个直接后果。第一,RTP 内的内存错误不会直接导致内核崩溃,系统可靠性提升。第二,每次系统调用都要做特权级切换和参数拷贝,延迟比内核内直接调用高。对于周期小于 1 ms 的硬实时任务,通常仍放在内核态执行;对于周期在 10 ms 以上、逻辑复杂且允许一定抖动的业务,放进 RTP 更合适。

四、实时性约束下的设计取舍

实时性对内存管理的核心要求是确定性:分配时间可预测、访问延迟可预测、不会因为缺页或碎片导致长尾延迟。围绕这一点,VxWorks 提供了多种机制,取舍如下:

机制确定性隔离性适用场景
memPartLib 固定分区高(O(1))低ISR、硬实时任务
memPartLib 可变分区中(碎片影响)低内核驱动、启动阶段
RTP 堆(malloc)低(缺页+锁)高非关键业务、复杂逻辑
共享内存 + 信号量中中RTP 间大数据传递

实践中常见的做法是:在系统启动阶段一次性预分配所有关键缓冲,运行期不再调用动态分配。例如一个 1 kHz 的控制任务,可以在初始化时用 memPartAlloc 从固定分区取出 4 个 2 KB 缓冲循环使用,避免运行期分配带来的抖动。

/* 示例:启动时预分配固定分区缓冲,运行期零动态分配 */
#define BUF_SIZE   2048
#define BUF_COUNT  4

char *ctrlBuf[BUF_COUNT];
STATUS initCtrlBuffers(void)
{
    int i;
    for (i = 0; i < BUF_COUNT; i++) {
        ctrlBuf[i] = (char *)memPartAlloc(ctrlPartId, BUF_SIZE);
        if (ctrlBuf[i] == NULL) {
            return ERROR;   /* 分区不足,启动即失败,避免运行期才发现 */
        }
    }
    return OK;
}
/* 运行期只做 ctrlBuf[idx] 的读写与索引轮转,不再 alloc/free */
判断依据:如果任务周期小于 1 ms,或对抖动要求小于 50 μs,优先使用内核态固定分区;如果任务周期大于 10 ms 且允许毫秒级抖动,可放入 RTP 以获得隔离保护。两者之间则根据故障影响面决定。
常见误区:在 ISR 中调用 malloc 或访问未锁定页。ISR 不能睡眠,缺页会直接导致系统异常;同时动态分配可能加锁,破坏中断响应确定性。ISR 只应使用预先分配好的固定缓冲。

总结来看,VxWorks 内存管理架构的本质是在“确定性”与“隔离性”之间做分层:内核态用固定分区保确定性,用户态用 MMU 保隔离性,共享内存做受控的数据交换。设计时先明确任务的周期与抖动上限,再决定它落在哪一层、用哪种分配器,最后把关键缓冲在启动阶段全部预分配完毕,运行期只做读写与轮转。这样得到的系统,内存行为才是可预测、可验证的。