就性能而言,为矩阵分配连续内存块与单独内存块有什么好处?即,而不是像这样编写代码:
char **matrix = malloc(sizeof(char *) * 50);
for(i = 0; i < 50; i++)
matrix[i] = malloc(50);
给我50个不同的50个字节的块和一个50个指针的块,如果我改为写的话:
char **matrix = malloc(sizeof(char *) * 50 + 50 * 50);
char *data = matrix + sizeof(char *) * 50;
for(i = 0; i < 50; i++) {
matrix[i] = data;
data += 50;
}
给我一个连续的数据块,有什么好处?避免缓存未命中是我唯一能想到的,甚至只有少量数据(小到足以容纳缓存),对吧?我已经在一个小应用程序上测试了这个,并注意到一个小的加速,并想知道为什么。
答案 0 :(得分:3)
这很复杂 - 你需要衡量。
使用中间指针而不是计算二维数组中的地址很可能是当前处理器的损失,并且两个示例都是这样做的。
接下来,适合L1缓存的一切都是一个巨大的胜利。 malloc()最有可能四舍五入到64字节的倍数。 180 x 180 = 32,400字节可能适合L1缓存,而单个malloc可能分配180 x 192 = 34,560字节可能不适合,特别是如果你添加另外180个指针。
一个连续数组意味着您知道数据如何适合缓存行,并且您知道您在硬件中具有最少数量的页表查找。拥有数百个mallocs,无法保证。
答案 1 :(得分:0)
观看Scott Meyers&#39; &#34; CPU缓存和你关心的原因&#34; Youtube上的演示文稿。性能提升可以是整个数量级。
https://www.youtube.com/watch?v=WDIkqP4JbkE
至于上面的讨论,中间指针参数很久以前就已经死了。编译器将它们优化掉。 N维数组被分配为平坦的1D向量,总是如此。如果你做了std :: vector&gt;,那么你可能得到一个有序的向量前向列表,但对于原始数组,它们总是以平面方式分配为一个长的,连续的条带,并且是多维的访问减少到指针算术的方式与1维访问相同。
要访问数组[i] [j] [k](假设{A,B,C}的宽度,高度,深度),添加i *(B C)+(j C)+ k到阵列前面的地址。无论如何,你必须以一维表示手动进行数学运算。