GCC 版本:gcc 4.8.5
copt: -std=c++11 -O3
SIZE = 50 * 1024 * 1024
第一段代码:
int main() {
char* src = new char[SIZE];
char* dst = new char[SIZE];
memset(dst, 'a', SIZE);
for (size_t i = 0; i < 5; ++i) {
size_t start = now();
memcpy(dst, src, SIZE);
cout << "timer:" << now() - start << "ms" << endl;
}
return 0;
}
输出:
timer:5ms
timer:4ms
timer:5ms
timer:5ms
timer:4ms
第二段代码:
int main() {
char* src = new char[SIZE];
char* dst = new char[SIZE];
memset(src, 'a', SIZE);
memset(dst, 'a', SIZE);
for (size_t i = 0; i < 5; ++i) {
size_t start = now();
memcpy(dst, src, SIZE);
cout << "timer:" << now() - start << "ms" << endl;
}
return 0;
}
输出:
timer:9ms
timer:8ms
timer:8ms
timer:8ms
timer:8ms
第三段代码:
int main() {
char* src = new char[SIZE];
char* dst = new char[SIZE];
for (size_t i = 0; i < 5; ++i) {
size_t start = now();
memcpy(dst, src, SIZE);
cout << "timer:" << now() - start << "ms" << endl;
}
return 0;
}
输出:
timer:22ms
timer:4ms
timer:5ms
timer:5ms
timer:5ms
总结:
- 比较第一和第三种情况:第三种情况的第一轮慢是因为轻微的页面错误。
问题:
为什么在第一种情况下,memcpy src 不会触发任何小页面错误?
为什么在第二种情况下,比第一种情况慢 1 倍。操作系统有什么优化吗?
最佳答案
Memcpy 受外部存储器吞吐量的限制;看起来操作系统能够虚拟地将内存分配到页表中并执行 Copy-on-write .这可以解释这两种现象:只有一个物理内存块保留给未修改的 src
,在情况 2 和 3 中,它位于最快的缓存中。如果一个所有的内存访问都会上下移动到外部存储器。案例 2 的运行 1 中的 5 倍速度损失是由于虚拟分配的 src
在写入时被复制到唯一的物理页面。
连续 N 次对初始 memset
计时应该可以证实假设。
The copy-on-write technique can be extended to support efficient memory allocation by having a page of physical memory filled with zeros. When the memory is allocated, all the pages returned refer to the page of zeros and are all marked copy-on-write. This way, physical memory is not allocated for the process until data is written, allowing processes to reserve more virtual memory than physical memory and use memory sparsely, at the risk of running out of virtual address space.
关于c++ - 奇怪的行为 : memcpy faster 1x when src is not set value,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47027666/