2012-04-24 2 views
12

Я пишу программу, которая получает огромное количество данных (в разных размерах) из сети, обрабатывает их и записывает их в память. Поскольку некоторые части данных могут быть очень большими, мой текущий подход ограничивает используемый размер буфера. Если кусок больше максимального размера буфера, я записываю данные во временный файл и затем читаю файл в кусках для обработки и постоянного хранения.mmap и использование памяти

Мне интересно, можно ли это улучшить. Я читал о mmap некоторое время, но я не уверен на сто процентов, если это может мне помочь. Моя идея - использовать mmap для чтения временного файла. Помогает ли это в любом случае? Главное, о чем я беспокоюсь, это то, что иногда большая часть данных не должна заполнять мою основную память, из-за чего все остальное должно быть заменено.

Также, как вы считаете, подход с временными файлами полезен? Должен ли я это делать или, может быть, должен ли я доверять менеджеру Linux-памяти для выполнения этой работы? Или я должен вообще что-то сделать?

+0

Насколько велик «большой»? Самое главное, как это соотносится с общей реальной ОЗУ на компьютере, где это будет работать? – zwol

+0

Большой - это несколько гигабайт. У меня 24G RAM, поэтому некоторые файлы могут занимать до четверти физической памяти или даже больше. – Elektito

+1

В основном, используя 'mmap()', вы заставляете эту память копировать файл, а не подкачиваться подкачкой (так называемая анонимная память). Под давлением памяти ядро ​​может решить вернуть память с файловой памятью более агрессивно, чем анонимная память, или это может сделать обратное, я не знаю. – ninjalj

ответ

10

ММАП может помочь вам в каком-то смысле, я объясню некоторые гипотетические примеры:

Первое: Допустим, вы работаете из памяти, и ваше приложение, которое имеет 100MB кусок malloc'ed память получает 50% от нее, это означает, что ОС должна была записать 50 МБ в файл подкачки, и если вам нужно его прочитать, вы написали, заняли, а затем снова прочитали 50 Мб вашего файла подкачки.

В случае, если память была только mmap'ed, операционная система не будет записывать эту информацию в файл подкачки (поскольку он знает, что эти данные идентичны самому файлу), вместо этого он просто поцарапает 50 МБ (опять же: предположим, что вы ничего не писали на данный момент), и все. Если вам когда-либо понадобится, чтобы память читалась снова, ОС будет извлекать содержимое не из файла подкачки, а из исходного файла, который вы нарисовали, поэтому, если для любой другой программы требуется 50 Мбайт свопа, они доступны. Также нет накладных расходов при работе с файлами подкачки.

Предположим, вы прочитали блок данных объемом 100 Мбайт, и согласно начальному 1МБ данных заголовка информация, которую вы хотите, расположена со смещением 75 МБ, поэтому вам не нужно ничего между 1 ~ 74,9 МБ! Вы прочитали его только для того, чтобы сделать ваш код более простым. С помощью mmap вы будете только читать данные, к которым вы действительно обращались (округленный 4kb или размер страницы ОС, который в основном составляет 4kb), поэтому он будет читать только первый и 75-й MB. Я думаю, что очень сложно сделать более простой и эффективный способ избежать чтения диска, чем файлы mmaping. И если по какой-то причине вам нужны данные со смещением 37MB, вы можете просто использовать его! Вам не нужно снова копировать его, так как весь файл доступен в памяти (конечно, ограниченным объемом памяти вашего процесса).

Все файлы mmap'ed подкрепляются сами по себе, а не файлом подкачки, файл подкачки предназначен для предоставления данных, у которых нет файла для резервного копирования, обычно это данные malloc'ed или данные, которые поддерживаются но он был изменен и [не может/не должен] быть записан обратно до него, прежде чем программа на самом деле сообщает OS об этом с помощью вызова msync.

Остерегайтесь того, что вам не нужно отображать весь файл в памяти, вы можете сопоставить любую сумму (2-й arg - «size_t length»), начиная с любого места (6-й arg - «off_t offset»), но если ваш файл, вероятно, будет огромным, вы можете безопасно отображать 1 ГБ данных без страха, даже если система упаковывает только 64 МБ физической памяти, но это для чтения, если вы планируете писать, тогда вы должны быть более консервативными и отображать только что вам нужно.

Картографические файлы помогут вам сделать ваш код более простым (у вас уже есть содержимое файла в памяти, готовое к использованию, с гораздо меньшими издержками памяти, поскольку оно не является анонимной памятью) и быстрее (вы будете только читать данные, доступ к программе).

+0

Спасибо. Хорошо знать все это, но, к сожалению, большая часть этого не относится к моей нынешней ситуации. – Elektito

3

Главное преимущество mmap с большими файлами состоит в том, чтобы совместно использовать одно и то же сопоставление памяти между двумя или более файлами: если вы mmap с MAP_SHARED, он будет загружен в память только один раз для всех процессов, которые будут использовать данные с помощью сохранение памяти.

Но AFAIK, mmap отображает весь файл в память (Here, вы можете найти примеры того, как mmap выходит из строя с файлами, большими, чем физическое пространство mem + swap.), Поэтому, если вы получаете доступ к файлу из одного процесса, это не поможет вы с потреблением физической памяти.

+0

Так есть ли другой способ, я могу убедиться, что не все файлы загружены в память? Понимаете, у меня другая проблема. Мне нужно отправить данные для хранения в MongoDB. Теперь Mongo нуждается в том, чтобы я дал ему указатель на некоторый буфер в памяти, и поэтому кажется, что независимо от того, загружаю ли я сам файл или использую mmap, файл будет храниться в памяти в своем пространстве в течение определенного периода времени. – Elektito

+2

Я не знаком с MongoDB, но если он хочет иметь в памяти буфер, содержащий весь файл, то мне кажется, что нет смысла использовать временные файлы вообще. Если поведение, когда вы читаете прямо из сети в буферы памяти, а затем передаете их в MongoDB, неприемлемо, я думаю, вам придется разбивать большие файлы на куски * в базе данных *. – zwol

+0

mmap действительно «отображает весь файл в память», но он не * читает его с диска в память * для этого. Отображение файлов, больших, чем физическое mem + swap, может привести к сбою только в том случае, если вы используете определенные флаги или очень специфические конфигурации ядра (которые обычно не используются), или если вы пытаетесь mmap-файлы с общим размером, превышающим вашу * виртуальную * память. Устранение виртуальной памяти - настоящая угроза для 32-битных систем, но что-то еще не должно приводить к тому, что mmap не будет работать, когда вы сделаете это правильно. – user1643723

1

Я считаю, что mmap не требует, чтобы все данные были в памяти в тот же момент - он использует кеш страницы, чтобы сохранить недавно использованные страницы в памяти, а остальное на диске.

Если вы читаете один кусок за раз, использование временного файла, вероятно, вам не поможет, но если вы одновременно читаете несколько кусков, используя несколько потоков, процессов или используя select/poll, то это может произойти.