我有简单的C代码(psuedo代码):
#define N 100000000
int *DataSrc = (int *) malloc(N);
int *DataDest = (int *) malloc(N);
memset(DataSrc, 0, N);
for (int i = 0 ; i < 4 ; i++) {
StartTimer();
memcpy(DataDest, DataSrc, N);
StopTimer();
}
printf("%d\n", DataDest[RandomInteger]);
我的电脑:Intel Core i7-3930,4x4GB DDR3 1600内存,运行RedHat 6.1 64位。
第一个memcpy()以1.9 GB /秒的速度发生,而接下来的三个以6.2 GB /秒的速度发生。 缓冲区大小(N)太大,不能由缓存效果引起。所以我的 第一个问题:为什么第一个memcpy()这么慢?也许malloc()在你使用它之前没有完全分配内存?
如果我删除了memset(),那么第一个memcpy()以大约1.5 GB /秒的速度运行, 但接下来的三个以11.8 GB /秒的速度运行。几乎是加速的2倍。我的第二个问题: 如果我不调用memset(),为什么memcpy()会快2倍?
答案 0 :(得分:5)
这很可能是由于VM子系统中的延迟分配造成的。通常,当您分配大量内存时,只会实际分配前N个页面并将其连接到物理内存。当您访问前N页以外的页面时,会生成页面错误,并在“按需”按键上分配和连接其他页面。基础。
关于问题的第二部分,我相信一些VM实现实际上跟踪归零页面并专门处理它们。尝试将DataSrc
初始化为实际值(例如随机值)并重复测试。
答案 1 :(得分:5)
正如其他人已经指出的那样,Linux使用optimistic memory allocation strategy。
第一个和以下memcpy
之间的差异是DataDest
的初始化。
正如您已经看到的,当您消除memset(DataSrc, 0, N)
时,第一个memcpy
甚至更慢,因为必须同时分配源的页面。初始化DataSrc
和 DataDest
时,例如
memset(DataSrc, 0, N);
memset(DataDest, 0, N);
所有memcpy
s的运行速度大致相同。
对于第二个问题:当您使用memset
初始化已分配的内存时,所有页面将连续布局。另一方面,当您在复制时分配内存时,源页面和目标页面将被交错分配,这可能会有所不同。