为什么fopen / fgets使用mmap和read系统调用来访问数据?

时间:2011-08-12 19:47:27

标签: c linux file mmap

我有一个小示例程序,只需fopen个文件并使用fgets来读取它。使用strace,我注意到第一次调用fgets运行mmap系统调用,然后读取系统调用用于实际读取文件的内容。在fclose上,文件为munmap。如果我改为打开直接读取文件,这显然不会发生。我很好奇这个mmap的目的是什么,以及它正在实现什么。

在我的基于Linux 2.6.31的系统上,当虚拟内存需求很大时,这些mmap有时会挂起几秒钟,在我看来是不必要的。

示例代码:

#include <stdlib.h>
#include <stdio.h>
int main ()
{
   FILE *f;
   if ( NULL == ( f=fopen( "foo.txt","r" )))
   {
     printf ("Fail to open\n");
   }
   char buf[256];
   fgets(buf,256,f);
   fclose(f);
}

以上是运行上述代码时的相关strace输出:

open("foo.txt", O_RDONLY)               = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=9, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb8039000
read(3, "foo\nbar\n\n"..., 4096)        = 9
close(3)                                = 0
munmap(0xb8039000, 4096)                = 0

4 个答案:

答案 0 :(得分:15)

这不是mmap编辑的文件 - 在这种情况下,mmap是匿名使用的(不是在文件上),可能是为后续读取将使用的缓冲区分配内存。 / p>

malloc实际上导致对mmap的调用。同样,munmap对应于对free的调用。

答案 1 :(得分:5)

mmap未映射文件;相反,它为stdio FILE缓冲分配内存。通常malloc不会使用mmap来为这么小的分配服务,但似乎glibc的stdio实现直接使用mmap来获取缓冲区。这可能是为了确保页面对齐(尽管posix_memalign可以实现相同的目的)和/或确保关闭文件将缓冲区内存返回给内核。我质疑页面对齐缓冲区的用处。大概这是为了性能,但我看不出它会有什么帮助,除非你读取的文件偏移也是页面对齐的,即便如此,它似乎是一个可疑的微优化。

答案 2 :(得分:1)

从我读过的内存映射函数在处理大文件时很有用。现在大的定义是我不知道的。但是对于大文件来说,与“缓冲”的i / o调用相比,它们明显更快。

在您发布的示例中,我认为文件是由open()函数打开的,而mmap用于分配内存或其他内容。

从mmap函数的语法中可以清楚地看到:

void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off);

第二个参数采用非负的文件描述符。 在堆栈跟踪中,它是-1

答案 3 :(得分:0)