SoA 架构
Rinne 为极致吞吐量而生。虽然大多数 JavaScript 库使用 对象数组 (AoS) 存储数据,但 Rinne 内核采用了 结构体数组 (SoA) 布局。
AoS vs. SoA
Section titled “AoS vs. SoA”对象数组 (AoS - Array of Objects)
Section titled “对象数组 (AoS - Array of Objects)”const particles = [ { x: 0, y: 0, z: 0 }, { x: 1, y: 1, z: 1 }];在 AoS 中,属性分散在堆内存中。当 CPU 尝试更新 50,000 个粒子时,会面临频繁的 缓存失效 (Cache Miss)。
结构体数组 (SoA - Structure of Arrays)
Section titled “结构体数组 (SoA - Structure of Arrays)”const xBuffer = new Float64Array(50000);const yBuffer = new Float64Array(50000);const zBuffer = new Float64Array(50000);Rinne 将属性存储在连续的 Float64Array 缓冲区中。这确保了当 CPU 处理一个粒子时,后续的几十个粒子的数据已经预加载到了 L1/L2 缓存中。
- 零对象分配:Rinne 在
tick()循环中不创建任何临时对象。 - 内存局部性:顺序内存访问模式允许现代 CPU 高效执行预取。
- SIMD 就绪:SoA 布局使得将来将计算卸载到 WebWorker 或使用 SIMD 指令变得极其简单。
在我们的压力测试中,Rinne 可以在标准 V8 引擎上以不到 1.3ms 的帧预算维持 50,000 个活跃节点。