Appearance
计算机体系与性能 共70题
说明:
- 高频方向:CPU Cache、局部性、cache line、cache miss、内存对齐、大小端、流水线、分支预测、SIMD、false sharing、AoS/SoA、内存池、性能分析。
一、单选题
1. CPU Cache 的主要作用是?
A. 缓解 CPU 与内存速度差距
B. 替代所有内存
C. 保存网络连接
D. 压缩纹理
答案:A
解析:Cache 位于 CPU 和主存之间,用更快的小容量存储缓存近期访问数据。
2. 程序顺序访问数组通常性能较好的主要原因是?
A. 空间局部性好,缓存命中率高
B. 数组不占内存
C. CPU 不需要执行指令
D. 编译器会删除循环
答案:A
解析:连续内存访问更容易命中同一缓存行,也利于硬件预取。
3. 时间局部性指的是?
A. 近期访问过的数据很可能再次被访问
B. 相邻地址容易被访问
C. 时间越长数据越快
D. 线程越多越快
答案:A
解析:时间局部性强调同一数据的重复访问。
4. 空间局部性指的是?
A. 访问某地址后,附近地址也可能被访问
B. 同一数据会被重复访问
C. 所有数据都在寄存器
D. 磁盘比内存快
答案:A
解析:数组遍历常利用空间局部性。
5. Cache line 通常指?
A. Cache 与内存交换数据的基本块
B. 一行 C++ 代码
C. 网络包头
D. 屏幕扫描线
答案:A
解析:CPU 缓存按缓存行加载数据,常见大小如 64 字节。
6. cache miss 会导致?
A. CPU 等待更慢层级缓存或内存
B. 程序一定崩溃
C. 网络断开
D. 显卡重启
答案:A
解析:miss 会增加访存延迟,可能成为性能瓶颈。

7. 以下哪种数据结构通常更 cache-friendly?
A. 连续数组
B. 随机分布链表
C. 大量指针跳转树
D. 碎片化对象链
答案:A
解析:连续数组有更好的空间局部性和预取效果。
8. 结构体内存对齐的主要目的之一是?
A. 满足硬件访问要求并提升访问效率
B. 让代码行数更少
C. 避免网络丢包
D. 替代虚函数
答案:A
解析:对齐可减少非对齐访问开销,某些平台还要求特定对齐。
9. 结构体 padding 指的是?
A. 编译器为满足对齐插入的填充字节
B. 网络填充包
C. 纹理压缩块
D. 栈溢出
答案:A
解析:成员之间或尾部可能插入 padding,影响 sizeof。
10. 大小端 endian 描述的是?
A. 多字节数据在内存中的字节顺序
B. CPU 核心数量
C. 网络延迟
D. 显卡纹理格式
答案:A
解析:小端低有效字节在低地址,大端高有效字节在低地址。
11. x86/x64 常见字节序是?
A. 小端
B. 大端
C. 随机端
D. 网络端
答案:A
解析:主流 x86/x64 平台通常为 little-endian。
12. 网络字节序通常是?
A. 大端
B. 小端
C. 随机端
D. 和显卡一致
答案:A
解析:网络协议通常使用 big-endian,又称 network byte order。
13. CPU 流水线的目的主要是?
A. 提高指令吞吐率
B. 让单条指令完全不耗时
C. 替代内存
D. 保证不发生分支
答案:A
解析:流水线让多条指令不同阶段重叠执行。
14. 分支预测失败通常会导致?
A. 流水线冲刷,性能下降
B. 内存容量增加
C. 网络包变大
D. 代码无法编译
答案:A
解析:预测失败需要丢弃错误路径上的流水线结果。
15. SIMD 的含义更接近?
A. 单指令多数据
B. 单数据多指令
C. 网络多播
D. 磁盘阵列
答案:A
解析:SIMD 可用一条指令处理多个数据元素,适合向量/矩阵/批量计算。
16. false sharing 指的是?
A. 多个线程修改同一缓存行中的不同变量导致缓存一致性抖动
B. 变量名相同
C. 共享指针为空
D. 两个文件同名
答案:A
解析:虽然变量不同,但在同一 cache line 上,跨核写入会互相使缓存失效。
17. 多线程程序中频繁写同一缓存行可能导致?
A. 缓存一致性流量增加
B. GPU 纹理变清晰
C. 磁盘更快
D. 网络更稳定
答案:A
解析:跨核心缓存行所有权来回迁移会降低性能。
18. 内存带宽瓶颈通常表示?
A. CPU/GPU 等待数据搬运,计算单元未充分利用
B. 代码没有函数
C. 网络端口不足
D. 硬盘没有分区
答案:A
解析:大量数据读写可能受限于内存带宽,而非计算能力。
19. AoS 指的是?
A. Array of Structures
B. Always on Server
C. Area of Shader
D. Async over Socket
答案:A
解析:AoS 是结构体数组,如 vector<Player>。
20. SoA 指的是?
A. Structure of Arrays
B. Socket over API
C. Shader of Alpha
D. Stack of Args
答案:A
解析:SoA 把字段拆成多个数组,有利于批量访问某一字段。
21. 在只批量更新位置 x 坐标时,SoA 相比 AoS 的潜在优势是?
A. 更少无关字段被加载进缓存
B. 一定减少代码量
C. 完全不占内存
D. 禁止 SIMD
答案:A
解析:SoA 能只访问需要的字段,提升缓存利用率和向量化机会。
22. 性能分析中,FPS 下降但 CPU/GPU 都不满,可能还要关注?
A. 同步等待、锁、I/O、内存带宽、调度抖动
B. 只看代码行数
C. 只看文件名
D. 只看显示器品牌
答案:A
解析:瓶颈可能来自等待和数据搬运,而非纯计算占满。
23. prefetch 预取的目的是什么?
A. 提前把可能访问的数据加载到缓存
B. 提前关闭程序
C. 提前发送网络 ACK
D. 提前删除纹理
答案:A
解析:合理预取可隐藏部分内存延迟,但错误预取也会污染缓存。
24. 循环展开 loop unrolling 的潜在收益是?
A. 减少循环控制开销并暴露更多优化机会
B. 保证代码更短
C. 消除所有 cache miss
D. 自动修复 bug
答案:A
解析:循环展开可能提升指令级并行,但会增加代码体积。
25. 循环分块 tiling 常用于?
A. 提升缓存复用
B. 减少源文件数量
C. 改变网络协议
D. 禁用多线程
答案:A
解析:矩阵计算等场景通过分块让数据在 cache 中复用。
26. 内存池的主要性能收益是?
A. 减少频繁小对象分配释放开销和碎片
B. 提升网络带宽
C. 增加 CPU 核数
D. 自动压缩图片
答案:A
解析:游戏对象、消息包、粒子等高频对象常用池化。
27. 对象池如果复用对象时不重置状态,最可能导致?
A. 脏状态 bug
B. CPU 不能启动
C. 编译器崩溃
D. 网络协议改变
答案:A
解析:复用前必须清理状态,否则上一次使用的数据会泄漏到新逻辑。
28. 判断机器大小端时,常用方法是?
A. 写入多字节整数并查看最低地址字节
B. ping 本机
C. 读取显卡型号
D. 比较文件大小
答案:A
解析:例如 int x=1,查看首字节是否为 1。
29. volatile 在 C/C++ 中主要表示?
A. 对象可能被编译器无法感知的方式修改,限制优化
B. 保证线程同步
C. 保证原子性
D. 保证 cache 一致性
答案:A
解析:volatile 不是线程同步工具,不能替代 atomic/mutex。
30. 原子操作 atomic 的性能通常比普通变量访问?
A. 更高开销,尤其涉及跨核同步时
B. 一定更低开销
C. 完全一样
D. 不会生成机器指令
答案:A
解析:atomic 可能带来内存序和缓存一致性成本。
二、不定项选择题
1. 哪些做法通常有利于提高 cache 命中率?
A. 使用连续内存
B. 减少随机指针跳转
C. 按访问顺序组织数据
D. 频繁遍历链表随机节点
答案:A、B、C
解析:连续访问和减少指针跳转通常更 cache-friendly。
2. 哪些现象可能说明存在 cache miss 问题?
A. CPU 等待内存
B. 性能随数据规模增大突然下降
C. 链表随机访问慢
D. 顺序数组遍历很快
答案:A、B、C
解析:顺序数组快通常是利用了缓存。
3. 影响结构体 sizeof 的因素包括?
A. 成员大小
B. 成员顺序
C. 对齐规则
D. padding
答案:A、B、C、D
解析:结构体大小由成员和对齐共同决定。
4. 关于大小端,正确的是?
A. 小端低有效字节在低地址
B. 大端高有效字节在低地址
C. 网络字节序通常是大端
D. 大小端会影响多字节数据序列化
答案:A、B、C、D
解析:跨平台通信和文件格式需要明确字节序。
5. 可能导致 false sharing 的情况有?
A. 多个线程频繁写相邻变量
B. 变量位于同一 cache line
C. 跨核心缓存一致性反复失效
D. 每个线程只读常量
答案:A、B、C
解析:只读常量一般不会导致 false sharing。
6. 性能优化前应该做什么?
A. 测量和定位瓶颈
B. 建立基准数据
C. 确认 CPU/GPU/内存/I/O 谁是瓶颈
D. 凭感觉重写全部代码
答案:A、B、C
解析:先 profile 再优化,避免无效改动。
7. 游戏客户端 CPU 性能问题可能来自?
A. 脚本层和原生层频繁交互
B. 过多小对象分配
C. 锁竞争
D. 缓存不友好的数据布局
答案:A、B、C、D
解析:这些都是游戏客户端常见 CPU 问题来源。
8. 能提升数据局部性的方式包括?
A. 对象数组连续存储
B. SoA 数据布局
C. 按系统批量处理组件
D. 每帧随机访问大量散落对象
答案:A、B、C
解析:随机散落访问通常破坏局部性。
9. SIMD 适合哪些场景?
A. 批量向量计算
B. 矩阵运算
C. 粒子更新
D. 每个元素分支完全不同且不可预测
答案:A、B、C
解析:SIMD 适合相同操作作用于多份数据。
10. 分支预测更容易失败的场景包括?
A. 条件结果随机
B. 数据分布不可预测
C. 循环内大量不规则分支
D. 固定模式分支
答案:A、B、C
解析:固定模式分支更容易预测。
三、判断题
1. Cache 容量越大,访问延迟通常越低。
答案:错
解析:更大层级 cache 通常容量更大但延迟更高。
2. 顺序遍历数组通常比随机访问链表更容易利用缓存。
答案:对
解析:数组连续,链表节点可能散落。
3. 结构体成员顺序可能影响 sizeof。
答案:对
解析:调整成员顺序可能减少 padding。
4. volatile 可以替代 mutex 保证线程安全。
答案:错
解析:volatile 不提供互斥和原子性。
5. false sharing 中,不同线程访问的变量可以是不同变量。
答案:对
解析:关键是它们位于同一 cache line 且被频繁写。
6. 网络字节序通常是小端。
答案:错
解析:网络字节序通常是大端。
7. SIMD 可以让一条指令处理多个数据元素。
答案:对
解析:这是 single instruction multiple data。
8. 性能优化应该先测量再改代码。
答案:对
解析:没有 profile 容易优化错方向。
9. 内存池可以减少频繁分配释放的开销。
答案:对
解析:池化常用于高频小对象。
10. 分支预测失败不会影响流水线。
答案:错
解析:预测失败可能导致流水线冲刷。
四、填空题
1. Cache 利用的两个经典局部性是时间局部性和 ______ 局部性。
答案:空间
解析:空间局部性指附近地址可能很快被访问。
2. CPU 与内存之间交换数据的基本缓存块通常称为 cache ______。
答案:line
解析:缓存行是 cache 加载/失效的基本粒度。
3. 小端机器中,低有效字节存放在 ______ 地址。
答案:低
解析:little-endian:低字节低地址。
4. 网络字节序通常采用 ______ 端。
答案:大
解析:big-endian 是网络协议常见字节序。
5. SIMD 的中文含义可写作:单指令 ______ 数据。
答案:多
解析:single instruction multiple data。
6. 多个线程写同一 cache line 上不同变量造成的性能问题称为 ______ sharing。
答案:false
解析:false sharing 会造成缓存一致性抖动。
7. 结构体为满足对齐规则插入的无效字节称为 ______。
答案:padding
解析:padding 会影响结构体大小。
8. SoA 的全称是 Structure of ______。
答案:Arrays
解析:SoA 将字段拆成数组。
9. AoS 的全称是 Array of ______。
答案:Structures
解析:AoS 是结构体数组。
10. 性能分析工具中,cache-misses 常用于观察 ______ 未命中情况。
答案:缓存
解析:cache miss 指缓存未命中。
五、简答题
1. 解释时间局部性和空间局部性。
参考答案:时间局部性指刚访问过的数据很可能再次被访问,例如循环中反复使用同一变量;空间局部性指访问某地址后,附近地址也很可能被访问,例如顺序遍历数组。CPU Cache 和预取机制都依赖局部性提升性能。
2. 什么是 cache miss?为什么会影响游戏性能?
参考答案:cache miss 是 CPU 访问数据时未在当前缓存层级命中,需要访问更慢的下级缓存或内存。游戏每帧时间很短,大量随机访问、指针跳转或数据布局差会导致 CPU 等待内存,表现为帧耗时上升、卡顿。
3. 解释 false sharing。
参考答案:false sharing 指多个线程修改不同变量,但这些变量位于同一 cache line。由于缓存一致性协议以 cache line 为单位维护所有权,多个核心写入会让该缓存行在核心间反复失效和迁移,导致性能下降。
4. AoS 和 SoA 有什么区别?
参考答案:AoS 是结构体数组,适合一次处理单个对象的多个字段;SoA 是多个字段数组,适合批量处理某一类字段。游戏 ECS 和批量更新中,SoA 往往能减少无关字段加载,提高 cache 命中和 SIMD 机会。
5. 为什么结构体成员顺序会影响大小?
参考答案:编译器会根据成员对齐要求插入 padding。若小成员和大成员交错排列,可能产生更多填充。把大对齐成员集中排列,有时可以减少结构体大小,但还要考虑可读性和 ABI 约束。
6. 如何判断大小端?
参考答案:可以定义一个多字节整数如 uint32_t x = 1,再用 uint8_t* 查看最低地址字节。如果最低地址字节为 1,则为小端;如果为 0 且最高字节为 1,则为大端。
7. 游戏客户端性能优化为什么要先 profile?
参考答案:性能瓶颈可能在 CPU、GPU、内存带宽、I/O、锁等待、脚本交互等不同位置。没有数据就优化容易改错方向。profile 能确认热点函数、帧耗时、cache miss、GC/分配、锁等待和渲染瓶颈,再针对性处理。
六、场景分析题
1. 场景:游戏里有 10 万个粒子,每帧只更新 position 和 velocity,但数据结构是 struct Particle { pos; vel; color; lifetime; material; ... } 的数组。CPU 更新较慢,你会怎么优化?
参考答案:可以考虑从 AoS 改为 SoA,把 position、velocity、lifetime 等热字段拆成连续数组,更新时只加载需要字段,减少 cache line 中无关数据;批量循环处理,减少分支;尝试 SIMD;按活跃粒子紧凑排列;使用对象池避免频繁分配;profile cache miss 和循环热点,确认优化效果。
2. 场景:多线程更新玩家状态,每个线程写自己的计数器,但性能随线程数增加反而下降。请分析可能原因。
参考答案:可能是 false sharing:多个线程写的计数器相邻,位于同一 cache line,导致缓存行在核心间反复失效。解决方式包括为每个线程的数据做 cache line 对齐和 padding,使用线程本地存储,批量汇总结果,减少共享写。
3. 场景:某系统使用链表保存大量可见对象,每帧遍历做剔除,Profiler 显示 CPU 时间高。如何分析和优化?
参考答案:链表节点分散,遍历时 cache miss 多,预取效果差。可改为连续数组/vector 保存活跃对象,删除时使用 swap-remove 或延迟压缩;按空间区域分桶,减少遍历数量;热冷数据分离,只遍历剔除需要的包围盒和 transform;用 profile 对比 cache miss、遍历时间和内存占用。