【问题标题】:Why does this code cause page faults?为什么这段代码会导致页面错误?
【发布时间】:2015-01-21 23:57:27
【问题描述】:

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

输出如下所示:

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

#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;
}

【问题讨论】:

  • 你为什么用malloc()而不是new()
  • for (int i=0; i&lt;sz; i += 4096) data[i] = 1; 你应该确保你的索引在范围内
  • 大概是因为设置一个 shell 然后让它调用ps 使用了足够的内存,系统会分页出一些新创建的页面。你有多少内存?
  • @frp “不会改变结果。” 我不怀疑。但是对于 c++ 代码,您应该使用new(),或者更好的是std::vector&lt;char&gt;
  • @frp:顺便说一下,在linux上你可以直接从/proc/self/stat读取进程统计信息; minfltmajflt 是(当前)返回行中的第 10 个和第 12 个元素(这是一系列以空格分隔的字段,旨在与 scanf 一起阅读)。有关字段列表,请参阅 man 5 proc

标签: c++ linux memory


【解决方案1】:

库函数system 大致执行以下操作:

  1. 分叉,使用内存映像的副本创建一个新进程。
  2. 在子进程中,exec /bin/sh 将命令行选项 -c 和指示的命令传递给它,用新加载的 /bin/sh 替换新进程的内存映像。
  3. 在父进程(原始进程)中,等待子进程完成,并返回其状态码。

当进程执行fork时,系统希望避免复制整个内存映像以复制它。所以它只是复制页表,并将所有页面标记为“写时复制”,这需要将它们设置为只读,以便可以检测到写入。

随后的exec 会将页面标记为未共享,但它可能不会取消页面设置为只读,因此后续写入页面仍会触发次要页面错误,尽管处理程序会这样做什么都没有,因为该页面不再共享。

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

【讨论】:

    猜你喜欢
    • 2011-03-16
    • 1970-01-01
    • 2017-08-18
    • 1970-01-01
    • 1970-01-01
    • 2015-08-17
    • 1970-01-01
    • 1970-01-01
    • 2016-10-25
    相关资源
    最近更新 更多