0

0

c++的ECS架构中Archetype和Sparse Set是如何提升性能的? (内存布局)

尼克

尼克

发布时间:2026-01-12 14:26:03

|

150人浏览过

|

来源于php中文网

原创

Archetype 通过将相同组件集合的实体聚合成连续内存块并按列存储组件数据,使CPU缓存预取高效,遍历时避免随机访问;Sparse Set用dense/sparse双数组实现O(1)实体ID查找。

c++的ecs架构中archetype和sparse set是如何提升性能的? (内存布局)

Archetype 为什么能提升遍历性能

Archetype 的核心是把拥有相同组件集合的实体聚合成连续内存块,避免遍历时跳来跳去。比如 Position + Velocity 的实体全挤在一块数组里,CPU 缓存预取就能一次拉进多个对象,而不是在堆上随机找。

关键点在于:每个 Archetype 对应一个独立的 std::vector(或自定义连续容器),里面只存该组合的组件数据(通常按列存储,如所有 Position.x 连续、所有 Position.y 连续),而非实体对象本身。

  • 新增实体时,先查是否有匹配 Archetype;没有就新建,有就直接 push_back 到对应 vector 尾部
  • 删除实体时,不是 erase 中间元素(会破坏连续性),而是用末尾元素覆盖被删位置,再 pop_back
  • 组件增删会触发 Archetype 切换:实体数据从旧 Archetype 搬到新 Archetype,开销是一次 memcpy,但换来后续 N 次遍历的缓存友好

Sparse Set 如何加速实体 ID 查找

实体 ID 通常是稀疏整数(比如删过 ID=5 的实体,剩下 0,1,2,3,4,6,7…),直接用 std::vector 存储会导致大量空洞。Sparse Set 用两个数组配合解决这个问题:

  • m_dense:连续数组,存当前所有有效实体 ID(顺序不保证,但紧凑)
  • m_sparse:大小等于最大可能 ID 的数组,m_sparse[id] 存该 ID 在 m_dense 中的索引;若 ID 无效,则值为 -1 或超出 m_dense.size()

这样查某个 ID 是否存在、获取其内部索引,都是 O(1);插入/删除也是 O(1)(插入追加到 m_dense 并更新 m_sparse,删除则交换末尾元素并更新两个数组)。

立即学习C++免费学习笔记(深入)”;

Codiga
Codiga

可自定义的静态代码分析检测工具

下载
// 简化版 SparseSet::contains 实现
bool contains(EntityID id) const {
    return id < m_sparse.size() && m_sparse[id] < m_dense.size() && m_dense[m_sparse[id]] == id;
}

Archetype 和 Sparse Set 怎么协同工作

Archetype 管「数据怎么放」,Sparse Set 管「实体 ID 怎么映射」,两者分工明确但必须对齐:

  • 每个 Archetype 内部维护自己的 Sparse Set(或等价结构),用于快速定位某实体在该 Archetype 数据数组中的偏移
  • 全局 Entity Manager 用一个 Sparse Set 记录所有活跃实体,同时保存每个实体当前所属的 Archetype 指针/ID
  • 当系统要处理 Position + Velocity,它只遍历对应 Archetype 的数据块,而不用扫描全部实体——Sparse Set 确保这个“查找 Archetype”过程不拖慢整体

如果只用 Archetype 不管 ID 映射,那每次通过 ID 查组件就得线性扫所有 Archetype;如果只用 Sparse Set 不分 Archetype,那遍历组件时又回到内存不连续的老问题。

容易被忽略的内存细节

真正影响性能的不是“用了没用”,而是具体怎么布局:

  • Archetype 内部组件存储建议按 SoA(Structure of Arrays)而非 AoS(Array of Structures),比如 std::vector positions_x;std::vector positions_y; 分开,方便 SIMD 向量化
  • Sparse Set 的 m_sparse 数组如果太大(比如支持 2^32 个 ID),会吃掉几 GB 内存——实际项目常用 16 位或 24 位 ID,配合分段 Sparse Set 或哈希 fallback
  • Archetype 切换时的数据搬运,若组件含非 trivial 构造/析构(比如 std::string),memcpy 会出错;必须用 placement new + 析构函数手动管理

这些细节不写进代码注释、不测 cache miss 率、不看 perf report,很容易以为“架构对了就一定快”。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

388

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

571

2023.08.10

CSS position定位有几种方式
CSS position定位有几种方式

有4种,分别是静态定位、相对定位、绝对定位和固定定位。更多关于CSS position定位有几种方式的内容,可以访问下面的文章。

81

2023.11.23

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

34

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

14

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

33

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

18

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

12

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
10分钟--Midjourney创作自己的漫画
10分钟--Midjourney创作自己的漫画

共1课时 | 0.1万人学习

Midjourney 关键词系列整合
Midjourney 关键词系列整合

共13课时 | 0.9万人学习

AI绘画教程
AI绘画教程

共2课时 | 0.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号