C++ 堆分配如何影响硬件缓存命中率?

C++ 堆分配如何影响硬件缓存命中率?,c++,caching,heap,C++,Caching,Heap,我做了一些测试来研究堆分配和硬件缓存行为之间的关系。实证结果很有启发性,但也可能误导,特别是在不同平台和复杂/不确定的用例之间 我感兴趣的场景有两种:批量分配(实现自定义内存池)或后续分配(信任操作系统) 下面是C语言中的两个分配测试示例++ //Consequent allocations for(auto i = 1000000000; i > 0; i--) int *ptr = new int(0); store_ptr_in_some_container(ptr)

我做了一些测试来研究堆分配和硬件缓存行为之间的关系。实证结果很有启发性,但也可能误导,特别是在不同平台和复杂/不确定的用例之间

我感兴趣的场景有两种:批量分配(实现自定义内存池)或后续分配(信任操作系统)

下面是C语言中的两个分配测试示例++

//Consequent allocations
for(auto i = 1000000000; i > 0; i--)
    int *ptr = new int(0);
    store_ptr_in_some_container(ptr);

//////////////////////////////////////

//Bulk allocation
int *ptr = new int[1000000000];
distribute_indices_to_owners(ptr, 1000000000);
我的问题是:

  • 当我为一个只读操作迭代所有这些操作时,如何缓存 CPU中的内存可能会自动分区吗

  • 尽管有实证结果(批量生产明显提升了性能 解决方案),当其他一些相对非常小的 大容量分配覆盖以前分配的缓存

  • 为了避免代码膨胀并保持代码可读性,将两者混合使用是否合理

  • 在这些概念中,
    std::vector
    std::list
    std::map
    std::set
    代表什么


通用堆分配器有一组难以解决的问题。它需要确保释放的内存可以回收,必须支持任意大小的分配,并强烈避免堆碎片

这将始终包括每次分配的额外开销,以及分配器需要的簿记。它至少必须存储块的大小,以便在释放分配时能够正确地回收它。而且几乎总是一个偏移量或指向堆段中下一个块的指针,分配大小通常比请求的大,以避免碎片问题

当然,这种开销会影响缓存效率,当元素很小时,您会情不自禁地将其放入一级缓存,即使您从未使用过它。当您一口气分配数组时,每个数组元素的开销为零。而且您很难保证每个元素在内存中都是相邻的,因此按顺序迭代数组的速度将与内存子系统支持的速度一样快

对于通用分配器来说,情况并非如此,因为分配量非常小,所以开销可能为100%到200%。当程序运行了一段时间并且重新分配了数组元素时,也不能保证顺序访问。值得注意的是,您的大型阵列无法支持这样一种操作,因此请小心,不要自动假定分配长期无法释放的大型阵列必然会更好

所以,是的,在这个人工场景中,你很可能会领先于大型阵列


Scratch std::list从引用的集合类列表中,它的缓存效率非常低,因为下一个元素通常位于内存中完全随机的位置。向量是最好的,只是引擎盖下的一个数组。映射通常是用红黑树完成的,这是合理的,但您使用的访问模式当然很重要。std::set也一样。

谢谢您的回答。我知道std::list实际上处于一个完全不同的位置。为了完整起见,我把它放在那里了。我会在几天内把它标记得最好,除非出现更长的版本。