Linux 内核 /proc/$PID/maps 中的脏页统计

Linux 内核 /proc/$PID/maps 中的脏页统计

太长了;内核到底如何能够在/proc/$PID/maps.

考虑以下 C 程序语句

static char page1[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE)))

现在,未初始化的变量在开始时为零。我的理解是,在程序启动时,内核将未初始化的变量映射到零页,并对页面进行写时复制延迟分配。很好,这样当页面错误发生时,内核可以解释未初始化部分的脏页。

现在考虑一下这个声明

static char page1[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE))) = {'c'}

这里,加载器将在程序初始化时加载 page1 的值,并将该页标记为 RW。因此,程序完成的任何写入对于内核来说都必须是不可见的,因为不会触发页面错误。

这是我为实验而编写的程序。

#define PAGE_SIZE (4*1024)
static char page1[PAGE_SIZE] __attribute__ ((aligned (PAGE_SIZE))) = {'c'};
int main()
{
  char c; int i; int *d;
  scanf("%c", &c);                // --------- tag 1
  for(i = 0; i < PAGE_SIZE; i++)
    {
      page1[i] = c;               // --------- tag 2
    }
  d = malloc(sizeof(int));
  while(1);
  return 0;
}

现在,在标签 1(代码中的注释)之前和之后,/proc/$PID/smaps包含的部分的输出page1粘贴在下面的表中

斯图 标签 1 之前 TAG-2 之后
尺寸: 8 KB 8 KB
内核页面大小: 4 KB 4 KB
MMU页面大小: 4 KB 4 KB
RSS: 8 KB 8 KB
附: 8 KB 8 KB
共享_清理: 0 KB 0 KB
共享_脏: 0 KB 0 KB
私人_清洁 4 KB 0 KB
私人_肮脏 4 KB 8 KB
参考: 8 KB 8 KB
匿名的 4 KB 8 KB

正如您所看到的,粗体颜色的参数发生了变化。

问题

  1. 内核到底是怎么知道我写了这个页面的?
  2. 这个匿名字段是什么以及为什么会发生变化?

任何其他详细解释所有工作的页面/博客/手册都会有所帮助。

我猜:

也许内核将页面标记为 RO,即使它是 RW,以便触发页面错误并且可以进行计数。或者也许有其他进程不断地遍历进程的页表,但这太昂贵了。

答案1

  1. 在 Linux 支持的大多数(也许是全部,我没有检查过)架构上,MMU 会跟踪哪些页面是脏的。因此内核可以在页面初始化时清除页表项中的脏位,即使内容非零,并且MMU会在页面修改时更新它。

  2. 匿名内存是没有文件支持的内存。通过写入页面,您增加了非文件支持的内存量 - 在初始化时,它由可执行映像支持,但一旦更改就不再是。

要查看内核在何处检查脏页,请查看供参考pte_dirty

内核还维护有点“软脏”,可以从用户空间中清除并由检查点恢复使用。

相关内容