Вход:  Пароль:  
FreeSource: Технологии/MemoryMappedFiles ...
Free Source | Каталог | Изменения | НовыеКомментарии | Пользователи | Регистрация |

Memory Mapped Files (отображение файлов на память)

Предположим, что наша программа должна прочитать файл размером в несколько сотен мегабайт, и посчитать в нем статистику встречаемости разных символов. Задача выглядит тривиальной – открываем файл, читаем блоками, скажем, по 64Kb (экспериментально подобраная величина, которая часто оказывается оптимальной) и считаем в них статистику. Проще, вроде бы не придумаешь. Можно, конечно, считать сразу весь файл в память, но во-первых памяти может просто не хватить, а во-вторых мы все-таки в многозадачной ОС.


А теперь посмотрим что при этом происходит реально для каждого блока – блок
данных с диска пересылается в кэш (обычно используя, чтобы не загружать
процессор, дабы он мог в это время заняться другими делами), из этого кэша
данные копируются в наш буфер, в котором и производится обработка. При этом,
разумеется, данные в кэше обычно остаются. То же самое происходит со 
следующим блоком. В результате некоторое количество блоков просто занимают
кэш (мы ведь все равно читам файл последовательно), происходят лишнии
операции копирования (которые, в отличии от дисковых, во-первых забирают на 
себя ресурсы процессора, а во-вторых забивают кэш процессора, тем самым
тормозя всю систему в целом). Представим себе, что мы запустили одновременно
десяток таких программ. Часть памяти ушла впустую на буферы внутри программ,
хотя она нам в этот момент была бы так нужна в качестве дискового кэша, и 
огромное количество процессорного времени на тупое копирование по многу раз 
одинаковых данных. Неприятно.


В таких случаях на помощь и приходит mmap. Механизм его работы следующий –
как только происходит обращение к памяти по указателю, который нам возвратила
функция mmap генерируется исключение. Обработчик исключения загружает данные
с диска в кэш (если они еще не в кэше) и делает mapping (отображение) кэша
на адресное пространство приложения, после чего приложению дается право на 
чтение этих данных. В том случае, если данные из кэша выгружаются из памяти,
то отображение тоже убирается, и как только приложение опять попытается
обратиться к этим данным, сгенерируется исключение, и все повторится по 
новой. Это позволяет программисту вообще не заботиться об оптимизации работы
с диском – все это берет на себя механизм виртуальной памяти линукса.
В любом случае происходит экономия и памяти, и скорости (за счет отсутствия
копирования из кэша в буфер приложения). В случае же обращения к одним и тем
же данным несколькими приложениями это особенно заметно.


А теперь вернемся к примеру с подсчетом статистики по большому файлу. При 
попытке обратиться к самому первому байту генерируется исключение, происходит
подгрузка в кэш при необходимости и делается mapping. Программа считает
статистику по первой странице памяти, после чего опять генерируется
исключение, и подгружается вторая. Через некоторое время памяти начнет
нехватать, и те блоки памяти, которые дольше всего неиспользовались, начинают
заменяться на новые данные. То есть происходит нормальный процесс очистки
дискового буфера, который происходил бы и при обычном чтении(!), однако
благодаря использования механизмов mmap доступной кэш памяти стало больше
(ведь она не тратится на буферы внутри приложений).


А теперь что произойдет если я одновременно запущу несколько таких программ
– количество сэкономленной памяти будет еще больше, оно будет расти линейно с 
ростом использования этого механизма, как следствие и больше скорость работы
всей системы в целом. Кроме того responsability системы ощутимо повышается
– так как нет этих операций копирования больших блоков данных (которые
происходят, к тому же, внутри syscall'ов) и чтение с диска производится по 
факту необходимости данных, а не заранее, что делает поведение системы более
«плавным».

Ограничения


К сожалению, на 32-х битных системах адресное пространство пользовательских
приложений ограничено, и обычно не больше 3Gb. В это пространство должно
уместится приложение, все загружаемые им so-модули (shared objects), все его
данные и mapping'и файлов. Соответственно, если вы хотите работать с большими
файлами, то вам придется делать mapping не файла целиком, а отдельных его 
частей. Это нельзя считать недостатком, ибо обычный read/write метод работы
с файлами в подобной ситуации будет гораздо менее эффективен и удобен. Просто
если вам необходима работа с файлами очень большого размера, то вам, видимо,
придется делать mapping небольших блоков, и работать с ними.


See also: Copy On Write

mmap(2)
msync(2)
getpagesize(2)

(C) Денис Смирнов <mithraen@freesource.info>, 15 Oct 2001


Отзывы — здесь вы можете высказать своё мнение по поводу содержимого сайта
Ссылок на эту страницу нет


 
Файлов нет. [Показать файлы/форму]
Комментариев нет. [Показать комментарии/форму]