为什么此代码会导致页面错误?

时间:2015-01-21 23:57:28

标签: c++ linux memory

我分配512mb的内存,然后我修改每个第4096个字节(这会导致每个修改的次要页面错误,这就是我实际得到的)。但后来我重复相同的循环,它再次导致每个请求的页面错误。我的问题是,为什么?

输出如下:

enter image description here

但是,如果我从程序中删除调用ps,则执行第二个循环所需的时间要低得多,比如0.04s。为什么呢?

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <sstream>
#include <unistd.h>
using namespace std;

const int sz = 512 * 1024 * 1024;

int main()
{
    char * data = (char *)malloc(sz);
    if (data == 0) cout << "alloc fail";
    stringstream cmd;
    cmd << "ps -o min_flt,maj_flt " << getpid();
    system(cmd.str().c_str());
    cout << "start\n";
    clock_t start = clock();
    for (int i=0; i<sz; i += 4096)
        data[i] = 1;
    clock_t end = clock();
    double time1 = double(end-start) / CLOCKS_PER_SEC;

    system(cmd.str().c_str());

    start = clock();
    for (int i = 0; i < sz; i += 4096)
        data[i] = 1;
    end = clock();
    double time2 = double(end-start) / CLOCKS_PER_SEC;

    system(cmd.str().c_str());

    cout << time1 << " " << time2 << endl;
}

1 个答案:

答案 0 :(得分:3)

库函数system大致如下:

  1. 分叉,创建一个包含内存映像副本的新进程。
  2. 在子项中,exec /bin/sh将命令行选项-c和指示的命令传递给它,用新加载的/ bin /替换新进程的内存映像SH。
  3. 在父级(原始进程)中,等待子级完成,并返回其状态码。
  4. 当进程执行fork时,系统希望避免复制整个内存映像以便复制它。所以它只是重复页面表,并将所有页面标记为&#34; copy-on-write&#34;这需要将它们设置为只读,以便可以检测到写入。

    后续exec会将页面标记为非共享,但它可能不会取消将页面设置为只读,以便后续写入页面仍会触发次要页面错误,尽管处理程序由于页面不再共享,因此不会执行任何操作。

    实际上并不保证exec将在第二个写循环开始之前发生。您的机器很可能具有多个核心,因此两个进程很可能同时处于活动状态。由于exec可能需要一段时间才能完成设置,因此很有可能某些写循环甚至会在exec之前发生,也就是说在有任何线索表明复制之前-write是不必要的。