连续调用mmap,任何caching?

我读了一个载体,如:

int readBytes(string filename, vector<uint32_t> &v) { // fstat file, get filesize, etc. uint32_t *filebuf = (uint32_t*)mmap(0,filesize,PROT_READ, MAP_FILE|MAP_PRIVATE, fhand,0); v = std::vector<uint32_t>(filebuf,filebuf+numrecords); munmap(filebuf, filesize); } 

在main()我有两个连续的调用(纯粹作为一个testing):

 vector<uint32_t> v(10000); readBytes(filename, v); readBytes(filename, v); // ... 

第二个调用几乎总是给一个更快的时钟时间:

 Profile time [1st call]: 0.000214141 sec Profile time [2nd call]: 0.000094109 sec 

看看系统调用指出内存块是differend:

 mmap(NULL, 40000, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fe843ac8000 mmap(NULL, 40000, PROT_READ, MAP_PRIVATE, 4, 0) = 0x7fe843ac7000 

为什么第二个电话会更快? 巧合? 什么,如果有的话,被caching?

假设你正在谈论什么* NIX-ish,可能有一个页面缓存,其工作就是缓存这种数据来获得这种加速。 除非在调用这些页面之间有其他的东西出现,否则他们仍然会在那里。

所以,第一个电话可能需要:

  1. 分配页面
  2. 将页面映射到您的进程地址空间
  3. 将这些页面中的数据复制到您的矢量中(可能会从磁盘中错误地处理数据)

第二次调用可能会发现页面仍然在缓存中,只有:

  1. 将页面映射到您的进程地址空间
  2. 将这些页面的数据复制到您的矢量中(这次是预先错误的,所以这是一个简单的内存操作)

实际上,我跳过了一步:评论中的open / fstat步骤可能也会通过inode缓存加速。

请记住,您的程序会看到虚拟内存。 有一个映射表(“页表”),将您的程序看到的虚拟地址映射到真实的物理内存。 操作系统将确保两个mmap()调用将您的程序看到的两个不同的虚拟地址映射到相同的物理内存。 所以数据只需要从磁盘加载一次。

更多detal:

  • 第一个mmap():OS只记录映射
  • 当您实际尝试读取数据时:发生“页面错误”,因为数据不在内存中。 操作系统捕捉到,从磁盘读取数据到磁盘缓存,并更新页面表,以便您的程序可以直接从磁盘缓存中读取,然后自动恢复您的程序。
  • 首先munmap():OS禁用映射,并更新您的页面表,所以你不能再读取文件。 请注意,该文件仍在操作系统的磁盘缓存中。
  • 第二个mmap():OS只记录映射
  • 当您实际尝试读取数据时:发生“页面错误”,因为数据未映射。 操作系统捕捉到,注意到数据已经在磁盘缓存中,并更新页表,以便程序可以直接从磁盘缓存中读取,然后自动恢复程序。
  • 第二个munmap():操作系统禁用映射,并更新你的页面表,所以你不能再读取文件。 请注意,该文件仍在操作系统的磁盘缓存中。