Чи відкриваються файли процесами, завантаженими в оперативну пам’ять?


24

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

Процеси можуть використовувати інші файли, читати або записувати в них, а якщо вони роблять ці файли, називаються відкритими файлами. Існує команда , щоб отримати список всіх відкритих файлів усіх запущених процесів: lsof.

Гаразд, тому мені цікаво, якщо подвійне життя команди, одна на жорсткому диску, інша в оперативній пам’яті, також стосується інших файлів, наприклад, тих, у кого не запрограмовано логіки, а просто контейнери для дані.

Моє припущення, що файли, відкриті процесами, також завантажуються в оперативну пам’ять. Я не знаю, чи це правда, це просто інтуїція.

Будь ласка, хтось може це зрозуміти?


Відповіді:


27

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

Це неправильно (загалом). Коли програма виконується (через execve (2) ...), процес (запуск цієї програми) змінює свій віртуальний адресний простір і ядро ​​переконфігурує MMU для цієї мети. Читайте також про віртуальну пам'ять . Зверніть увагу , що прикладні програми можуть змінити своє ВАП , використовуючи ММАП (2) & munmap& mprotect (2) , також використовується динамічного компоновщика (див LD-Linux (8) ). Дивіться також madvise (2) & posix_fadvise (2) & mlock (2) .

Майбутні помилки сторінки буде оброблено ядром для завантаження (ліниво) сторінок з виконуваного файлу. Читайте також про молотіння .

Ядро підтримує великий кеш сторінки . Читайте також про копіювання під час написання . Дивіться також читати (2) .

Гаразд, тому мені цікаво, якщо подвійне життя команди, одна на жорсткому диску, інша в оперативній пам’яті, також стосується інших файлів, наприклад, тих, у кого не запрограмовано логіки, а просто контейнери для дані.

Для системних викликів, таких як read (2) & write (2) , також використовується кеш сторінок. Якщо дані, які слід прочитати, знаходяться в ній, IO диска не буде зроблено. Якщо потрібний IO диск, прочитані дані, ймовірно, будуть розміщені в кеш-пам'яті сторінки. Тож на практиці, якщо ви двічі виконаєте одну і ту ж команду, може статися, що жоден фізичний введення-вивід на диск не робиться вдруге (якщо у вас старий обертовий жорсткий диск - не 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по черзі (але читайте розуміння "IFS = read -r рядок" ).

Обробка файлів по черзі в оболонці потрібна лише рідко, оскільки більшість утиліт все одно орієнтована на рядки (див. Чому використання циклу оболонки для обробки тексту вважається поганою практикою? ).

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

Навіть у форматах файлів, не орієнтованих на рядки, як-от JSON чи XML, є потокові аналізатори, що дає можливість обробляти величезні файли, не зберігаючи їх у ОЗП.

З виконуваними файлами це трохи складніше, оскільки спільні бібліотеки можуть завантажуватися на вимогу та / або ділитися між процесами (див. , Наприклад, Завантаження спільних бібліотек та використання оперативної пам’яті , наприклад).

Кешування - це те, що я тут не згадував. Це дія використання оперативної пам'яті для зберігання часто доступних фрагментів даних. Менші файли (наприклад, виконувані файли) можуть кешуватися ОС, сподіваючись, що користувач зробить багато посилань на них. Окрім першого читання файлу, наступний доступ буде зроблений до оперативної пам’яті, а не до диска. Кешування, як буферизація вводу та виводу, зазвичай значною мірою прозоре для користувача, а обсяг пам'яті, який використовується для кешування речей, може динамічно змінюватися залежно від обсягу оперативної пам’яті, що виділяється програмами тощо.


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


Ви сказали, що можна завантажувати спільні бібліотеки в оперативну пам'ять, чи можна також завантажувати звичайний файл, який містить лише дані в оперативну пам’ять, навіть якщо це не мало б сенсу?
акулант

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.