指针向量与值向量 大内存块与小内存块的性能损失

Vector of pointers vs vector of values performance penalty for large vs small memory blocks

本文关键字:内存 向量 性能 损失 指针 大内      更新时间:2023-10-16

我执行了一个小型测试来确定访问指针向量与值向量的行为。事实证明,对于小内存块,两者的性能相同,但是,对于大内存块,存在显着差异。

这种行为的解释是什么?

对于在我的电脑上执行的以下代码,D=0 的差异约为 35%,而 D=10 的差异并不明显。

int D = 0;
int K = 1 << (22 - D);
int J = 100 * (1 << D);
int sum = 0;
std::vector<int> a(K);
std::iota(a.begin(), a.end(), 0);
long start = clock();
for (int j = 0; j < J; ++j)
    for (int i = 0; i < a.size(); ++i)
        sum += a[i];
std::cout << double(clock() - start) / CLOCKS_PER_SEC << " " << sum << std::endl;
sum = 0;
std::vector<int*> b(a.size());
for (int i = 0; i < a.size(); ++i) b[i] = &a[i];
start = clock();
for (int j = 0; j < J; ++j)
    for (int i = 0; i < b.size(); ++i)
        sum += *b[i];
std::cout << double(clock() - start) / CLOCKS_PER_SEC << " " << sum << std::endl;

从全局内存获取数据很慢,因此 CPU 有一小部分非常快的内存来帮助内存访问跟上处理器的步伐。在处理内存请求时,您的计算机将尝试加快对内存中单个整数或指针的未来请求,方法是在您请求的位置周围请求一大堆整数或指针并将它们存储在缓存中。一旦快速内存已满,每当请求新内容时,都必须摆脱其最不喜欢的位。

您的小问题可能完全或基本上适合缓存,因此内存访问速度非常快。大问题无法容纳在这么快的内存中,所以你有问题。向量存储为 K 个连续的内存位置。当你访问一个向量时int它会加载 int 和他附近的一些值,这些值可以立即使用。但是,当您加载int*时,它会加载指向实际值的指针以及其他几个指针。这会占用一些内存。然后,当您取消引用时*它会加载实际值,并可能加载附近的一些实际值。 这会占用更多内存。您不仅必须执行更多工作,而且还要更快地填满内存。时间的实际增加会有所不同,因为它高度依赖于体系结构、操作(在本例中为 + )和内存速度。此外,您的编译器将非常努力地工作以最大程度地减少延迟。