Открываются ли файлы процессами, загруженными в оперативную память?

Открываются ли файлы процессами, загруженными в оперативную память?

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

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

Хорошо, мне интересно, верна ли двойная жизнь команды — одна на жестком диске, другая в оперативной памяти — для других типов файлов, например, тех, в которых не запрограммирована логика, а они просто являются контейнерами для данных.

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

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

решение1

Нет, файл не считывается автоматически в память при его открытии. Это было бы ужасно неэффективно. 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строка за строкой (но не читайтеПонимание «IFS= read -r line»).

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

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

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

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

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


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

решение2

Однако при запуске команд копии их файлов с жесткого диска помещаются в оперативную память,

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

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

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

Хорошо, мне интересно, верна ли двойная жизнь команды — одна на жестком диске, другая в оперативной памяти — для других типов файлов, например, тех, в которых не запрограммирована логика, а они просто являются контейнерами для данных.

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

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

Смотрите такжеLinux съел мою оперативную памятьи выполните команды типа xosview, top, htopили cat /proc/self/mapsили cat /proc/$$/maps(см.процесс(5)).

P.S. Я ориентируюсь на Linux, но и другие ОС имеют виртуальную память и страничный кэш.

решение3

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

Связанный контент