Bevy Entity 实体设计

ZoOL 对 Bevy Entity 结构的源码级解读,解释分代索引如何解决 ECS 中的 ABA 问题。

源码结构

pub struct Entity {
    index: u32,
    generation: NonZeroU32,
}

打印输出示例: 1v1 = index 1, generation 1

问题来源: ABA 问题

ECS 架构会涉及大量实体创建/销毁,需要回收 ID。仅用 usize 索引会导致 ABA 问题:

1. 创建 A, index=0
2. 创建 B, index=1
3. A 保存了 B 的索引 1
4. 删除 B
5. 创建 C, 回收了 index=1
6. A 用 index=1 查询,以为是 B,实际是 C → 错误

解决方案: 分代索引 (Generational Indices)

复合索引,由两部分组成:

  1. Index: 唯一标识符,用于快速查找
  2. Generation: 计数器,区分同一索引在不同时间点上引用的对象

生命周期

创建 A     → key(0, gen=1)
删除 A     → 条目 gen 增至 2
回收创建 B → key(0, gen=2) → 新生成
A 的旧引用  → key(0, gen=1) → 与条目 gen=2 不匹配 → 返回空/无效

关键设计决策

  1. NonZeroU32 用于 generation — 允许 Option<Entity> 使用 niche optimization,节省空间
  2. u32 不是 usize — 64 位平台上仍保持 8 字节,但尝试减小内存占用
  3. index 重用、generation 递增 — 确保旧引用失效

参考资料

文件位置

/Users/zool/workspace/ZoOL's Valut/Bevy Entity 实体设计.md