Файлы открыты процессами, загруженными в RAM?

24

Команды , например sed, являются программами, а программы - это кодированная логика внутри файла, и эти файлы находятся где-то на жестком диске. Однако, когда команды выполняются, копия их файлов с жесткого диска помещается в оперативную память , где они оживают и могут что-то делать и называются процессами .

Процессы могут использовать другие файлы, читать или записывать их, и если они это делают, эти файлы называются открытыми файлами. Существует команда , чтобы получить список всех открытых файлов всех запущенных процессов: lsof.

Итак, что меня интересует, так это то, что двойная жизнь команды, одна на жестком диске, другая в ОЗУ, также справедлива для других типов файлов, например для тех, у которых нет запрограммированной логики, но они просто контейнеры для данные.

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

Пожалуйста, кто-нибудь может понять это?

sharkant
источник

Ответы:

27

Однако, когда команды выполняются, копия их файлов с жесткого диска помещается в ОЗУ,

Это неправильно (в общем). Когда программа выполняется (через execve (2) ...), процесс (выполняющий эту программу) меняет свое виртуальное адресное пространство, и ядро ​​реконфигурирует MMU для этой цели. Читайте также о виртуальной памяти . Обратите внимание, что прикладные программы могут изменять свое виртуальное адресное пространство с помощью mmap (2) & munmap& mprotect (2) , также используемого динамическим компоновщиком (см. Ld-linux (8) ). Смотрите также madvise (2) и posix_fadvise (2) & mlock (2) .

Будущие ошибки страниц будут обрабатываться ядром для загрузки (лениво) страниц из исполняемого файла. Читайте также о побеждении .

Ядро поддерживает большой кеш страниц . Читайте также о копировании при записи . Смотрите также readahead (2) .

Итак, что меня интересует, так это то, что двойная жизнь команды, одна на жестком диске, другая в ОЗУ, также справедлива для других типов файлов, например для тех, у которых нет запрограммированной логики, но они просто контейнеры для данные.

Для системных вызовов, таких как read (2) и write (2), также используется кеш страниц. Если данные для чтения находятся в нем, дисковый ввод-вывод не будет выполнен. Если требуется дисковый ввод-вывод, считанные данные, скорее всего, будут помещены в кеш страниц. Таким образом, на практике, если вы выполняете одну и ту же команду дважды, может случиться, что во второй раз на диск не будет выполнен физический ввод-вывод (если у вас старый вращающийся жесткий диск - не SSD - вы можете услышать это; или внимательно наблюдайте за светодиодом вашего жесткого диска).

Я рекомендую прочитать книгу « Операционные системы: три простых компонента» (бесплатно скачивается, один файл PDF на главу), которая объясняет все это.

Смотрите также Linux Ate My RAM команды и работать , как xosview, top, htopили cat /proc/self/mapsили cat /proc/$$/maps(см прок (5) ).

PS. Я сосредоточен на Linux, но другие ОС также имеют виртуальную память и кеш страниц.

Василий Старынкевич
источник
35

Нет, файл не будет автоматически считан в память при его открытии. Это было бы ужасно неэффективно. sedНапример, он читает строку ввода построчно, как и многие другие инструменты Unix. Он редко должен хранить в памяти больше текущей строки.

С awkэтим же. Он читает запись за раз, которая по умолчанию является строкой. Если вы храните части входных данных в переменных, это, конечно, будет лишним 1 .

Некоторые люди имеют привычку делать такие вещи, как

for line in $(cat file); do ...; done

Поскольку оболочке придется полностью развернуть $(cat file)подстановку команд перед запуском даже первой итерации forцикла, все это будет считано fileв память (в память, используемую оболочкой, выполняющей forцикл). Это немного глупо, а также не элегантно. Вместо этого нужно сделать

while IFS= read -r line; do ...; done <file

Это будет обрабатывать fileпострочно (но прочитайте Understanding "IFS = read -r line" ).

Обработка файлов строка за строкой в ​​оболочке требуется редко, так как большинство утилит в любом случае ориентированы на строки (см. Почему использование цикла оболочки для обработки текста считается плохой практикой? ).

Я работаю в области биоинформатики, и при обработке огромных объемов геномных данных я не смог бы многое сделать, если бы не хранил в памяти только те части данных, которые были абсолютно необходимы. Например, когда мне нужно отбросить биты данных, которые могут быть использованы для идентификации лиц из набора данных объемом 1 терабайт, содержащего варианты ДНК в файле VCF (поскольку данные этого типа не могут быть обнародованы), я делаю построчно обработка с помощью простой awkпрограммы (это возможно, поскольку формат VCF ориентирован на строки). Я не читаю файл в память, обрабатываю его там и снова записываю! Если файл был сжат, я бы передал его через zcatили gzip -d -c, который, поскольку gzipвыполняет потоковую обработку данных, также не прочитал бы весь файл в память.

Даже с форматами файлов, которые не ориентированы на строки, такими как JSON или XML, существуют потоковые парсеры, которые позволяют обрабатывать огромные файлы, не сохраняя их все в оперативной памяти.

С исполняемыми файлами это немного сложнее, поскольку разделяемые библиотеки могут быть загружены по требованию и / или могут быть разделены между процессами (см. , Например, Загрузка разделяемых библиотек и использование ОЗУ ).

Кеширование - это то, о чем я здесь не упоминал Это действие использования оперативной памяти для хранения часто используемых фрагментов данных. Меньшие файлы (например, исполняемые файлы) могут кэшироваться ОС в надежде, что пользователь сделает много ссылок на них. Помимо первого чтения файла, последующие обращения будут осуществляться к ОЗУ, а не к диску. Кэширование, подобно буферизации ввода и вывода, обычно в значительной степени прозрачно для пользователя, и объем памяти, используемой для кэширования, может динамически изменяться в зависимости от объема ОЗУ, выделенного приложениями и т. Д.


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

Кусалананда
источник
Вы сказали, что в ОЗУ можно загружать разделяемые библиотеки. Можно ли также загрузить в ОЗУ обычный файл, содержащий только данные, даже если это не имеет смысла?
Sharkant
1
@sharkant Конечно. Это только вопрос добавления данных в переменную (или в массив, или в хэш, или в любую другую структуру данных, предоставляемую рассматриваемым языком), пока весь файл не будет сохранен. С awk, { a[i++] = $0 }добавил бы все строки входного файла в массив a. Вы также можете поискать функцию C mmap(), но ее использование может быть немного не по теме.
Кусалананда
6
sed, awkи другие линейно-ориентированные программы не читают строки в памяти за раз, потому что простые текстовые файлы не содержат строкового индекса, а API файловой системы и низкоуровневое оборудование для хранения считывают один или несколько «секторов» (обычно 512 или 1024 байта) за один раз. Я был бы удивлен, если бы операционная система считала в память менее 8 КБ до обработки первой строки.
Рассел
5
Хотя подобная утилита sedбудет считывать в память только одну строку за раз, стоит упомянуть, что операционная система будет использовать свободный оперативный памяти для кэширования файлов, чтобы к ним можно было быстро получить доступ. Если вы работаете sedс меньшим файлом, вполне возможно, что ОС будет кэшировать весь файл в памяти, и операция будет выполнена полностью в оперативной памяти. Смотрите: en.wikipedia.org/wiki/Page_cache
Шон Доусон
5
@sharkant Есть смысл в том, чтобы файл был полностью доступен в памяти (см. другой ответ, здесь системный вызов ключевого слова - mmap). Например, система базы данных обычно хотела бы, чтобы для простоты и скорости доступа вся база данных или, по крайней мере, некоторые индексы отображались в памяти. Это не обязательно означает, что все это на самом деле в памяти. ОС может свободно «притворяться», что файл находится в памяти. Он сообщает приложению «здесь, в этом диапазоне памяти находится ваш файл», и только после того, как выполняется чтение (точно так же, как когда процесс был выгружен), данные фактически читаются.
Йонас Шефер
5

Нет. Хотя в наши дни концерты ОЗУ фантастические, было время, когда ОЗУ было очень ограниченным ресурсом (я изучал программирование на VAX 11/750 с 2 МБ ОЗУ), и единственной вещью в ОЗУ были активные исполняемые файлы и страницы данных. активных процессов и файлов данных, которые были в буферном кеше.
Буферный кеш был очищен, а страницы данных были заменены. И часто в разы. Исполняемые страницы только для чтения были перезаписаны, а таблицы страниц помечены так, что, если программа снова коснется этих страниц, они будут выгружены из файловой системы. Данные были выгружены из свопинга. Как отмечалось выше, библиотека STDIO собирала данные в блоках и получала их программой по мере необходимости: fgetc, fgets, fread и т. Д. С помощью mmap файл может быть отображен в адресное пространство процесса, как это делается с помощью объекты общей библиотеки или даже обычные файлы. Да, вы можете иметь некоторую степень контроля, если он находится в оперативной памяти или нет (mlock), но это только так далеко (см. Раздел кода ошибки mlock).

Роджер Л.
источник
1
Утверждение «ваша оперативная память будет слишком маленькой для ваших файлов» теперь верно, как это было в старые времена VAX.
Федерико Полони,
1
@Federico_Poloni Не совсем так сегодня. У моего последнего работодателя у нас был ПК класса рабочей станции с 1 ТБ ОЗУ и всего 0,5 ТБ жесткого диска. (Класс задачи: небольшие входы, средние выходы, большие массивы с произвольным доступом во время вычислений).
nigel222