CPU缓存预取以及确定数据下直接更改数组length的好处
- 1. CPU 缓存预取(Cache Preloading):
- CPU 缓存预取:
- 为什么反向填充栈能利用缓存预取:
- 2. 为什么可以直接改变数组的 length:
- 数组的动态长度:
- 为什么可以直接改变 length:
- 性能考虑:
- 总结:
1. CPU 缓存预取(Cache Preloading):
在这段代码中,findFSTNodeByDataName 使用了一个 stack 数组来存储待处理的节点,并且通过反向填充栈来优化性能,特别是在 CPU 缓存的使用上。
const stack = new Array(payload.length);
let stackIdx = payload.length;
// 反向填充初始栈(利用 CPU 缓存预取)
for (let i = 0; i < payload.length; i++) {
stack[i] = payload[i];
}
CPU 缓存预取:
- 在现代计算机中,CPU 会使用缓存(例如 L1/L2 缓存)来提高内存访问速度。访问较远的内存地址(比如跨越不同缓存块的数据)可能会导致较慢的访问速度。为了提高效率,CPU 会预取(预加载)一些内存块,提前将它们加载到缓存中,以减少等待时间。
为什么反向填充栈能利用缓存预取:
- 由于 stack[i] = payload[i] 是顺序访问数组的元素,而数组通常是按顺序存储在内存中的(尤其是在大数组或一维数组中)。访问内存时,CPU 会预取接下来的内存区域,因为数组的内存是线性分布的。因此,在这个循环中,填充栈的过程本身会触发CPU预取操作,使得数据在栈上被预加载,后续的栈操作就能更高效地访问这些数据。
- 更进一步,现代 JavaScript 引擎和操作系统会在物理内存中对数据进行布局优化,使得连续的内存区域更有可能被缓存(如数组元素连续存储在内存中)。通过反向填充(从栈顶往下填充),代码可能更好地利用了 CPU 的预取机制,提高了内存访问的效率。
2. 为什么可以直接改变数组的 length:
在这段代码中,当栈中某个节点有子节点时,代码改变了 stack 数组的 length:
const children = node.children;
if (children?.length) {
const childLen = children.length;
stack.length = stackIdx + childLen; // 改变数组长度
for (let j = 0; j < childLen; j++) {
stack[stackIdx + j] = children[j];
}
stackIdx += childLen;
}
数组的动态长度:
- 在 JavaScript 中,数组的 length 是一个动态属性,你可以随时通过设置 length 来扩展或收缩数组。当你设置 stack.length = stackIdx + childLen 时,实际上是调整了数组的大小,使它容纳更多的元素。需要注意的是,改变数组 length 只会影响已分配的数组内存(对于扩展数组会重新分配内存)。
为什么可以直接改变 length:
- JavaScript 数组是动态的,它们可以按需增加或缩小。虽然 length 是一个特殊的属性,但它与数组的元素存储是分开的。这使得在访问数组元素时,设置 length 会自动调整数组的大小,且这种操作不需要手动分配新的内存。JavaScript 引擎内部会自动管理数组内存的重新分配或收缩。
- 在这段代码中,stack.length = stackIdx + childLen 是为了将栈的长度调整到适应当前子节点的数量。这种做法与使用 push 或 unshift 添加元素相比,性能上会更高。通过直接设置 length,数组的内存布局会被调整,以便为新元素腾出空间。更重要的是,length 的操作不会导致 push 的隐式内存分配和元素复制过程。
性能考虑:
- 当你直接设置 length 时,相比 push 或 unshift,通常会避免不必要的内存重新分配和复制,尤其是在元素的数量已知或变化可控的情况下。这种方式避免了多次进行内存扩容操作,提高了性能。
总结:
1. CPU 缓存预取:通过反向填充栈,可以利用 CPU 的预取机制,提高内存访问效率。这种方法优化了内存布局,避免了频繁的随机内存访问,提高了缓存命中率。
2. 直接改变 length 的原因:在 JavaScript 中,数组的 length 可以直接修改,它是一个动态的属性。修改 length 不需要进行数组的复制或其他操作,因此相比 push 等方法,能更高效地调整数组的大小,避免了不必要的内存分配和数据复制。
这种技术的组合方式(使用反向填充和调整数组 length)可以帮助提升性能,尤其是在处理大量数据时,减少内存分配和复制的开销,进而提高算法效率。