Почему fopen/fgets используют как mmap, так и системные вызовы для доступа к данным?

У меня есть небольшая примерная программа, которая просто fopen файл и использует fgets для ее чтения. Используя strace, я заметил, что первый вызов fgets запускает системный вызов mmap, а затем чтение системных вызовов используется для фактического чтения содержимого файла. на fclose, файл munmap ed. Если я вместо этого прочитаю файл с открытым/прочитанным напрямую, это, очевидно, не произойдет. Мне интересно, какова цель этого 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

Ответ 1

Это не файл mmap 'ed - в этом случае mmap используется анонимно (не в файле), возможно, для выделения памяти для буфера, который будут использоваться последующие чтения.

malloc фактически приводит к такому призыву к mmap. Аналогично, munmap соответствует вызову free.

Ответ 2

mmap не отображает файл; вместо этого он выделяет память для буферизации stdio FILE. Обычно malloc не будет использовать mmap для обслуживания такого небольшого выделения, но, похоже, реализация glibc stdio использует mmap непосредственно для получения буфера. Вероятно, это необходимо для выравнивания по страницам (хотя posix_memalign мог бы достичь того же) и/или убедиться, что закрытие файла возвращает буферную память в ядро. Я сомневаюсь в полезности выравнивания по страницам буфера. Предположительно это для производительности, но я не вижу никакого способа помочь, если только смещение файла, которое вы читаете, также выровнено по страницам, и даже тогда это кажется сомнительной микро-оптимизацией.

Ответ 3

из того, что я читал, функции сопоставления памяти полезны при обработке больших файлов. теперь определение большого - это то, о чем я понятия не имею. но да для больших файлов они значительно быстрее по сравнению с "буферизованными" вызовами ввода/вывода.

в примере, который вы опубликовали, я думаю, что файл открывается функцией open(), а mmap используется для выделения памяти или чего-то еще.

из синтаксиса функции mmap это ясно видно:

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

второй последний параметр принимает дескриптор файла, который должен быть неотрицательным. в то время как в трассировке стека это -1