Как определить, отображается ли файл в памяти?

8

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

  1. Допустим, я перехожу к каталогу в моей файловой системе, и в этом каталоге есть файл. Возможно ли, чтобы этот файл указывал на область в основной памяти, а не на область на диске?
  2. Если это возможно, это то, что мы называем «файл с отображением в памяти»?
  3. Каков смысл перемещения такого файла по файловой системе (то есть переноса mvтакого файла из одного каталога в другой)? Что я понимаю, так как файл отображен в памяти, процесс (ы), взаимодействующий с файлом, всегда записывает в предопределенную область основной памяти, и когда мы открываем этот файл (например, используя vim), мы читаем эту область главного память (значит, диск не задействован). Следовательно, независимо от того, куда мы перемещаем файл, он всегда будет работать правильно, верно? Если да, имеет ли какое-либо значение перемещение файла вокруг файловой системы?
  4. Есть ли команда, которая скажет, сопоставлен ли файл с памятью?
  5. Наконец, если я открою файл с отображением в памяти vim, внесу в него некоторые изменения, сохраню и закрою vim, что произойдет? Будут ли мои изменения просто записываться в основную память? Если это так, другие процессы, использующие этот файл, увидят изменения, которые я только что сделал? По моему опыту, другие процессы не видели изменений, которые я внес в файл, когда я сделал некоторые изменения в файле с vim. Что является причиной этого?
Утка
источник
12
Это напоминает мне, что кто-то спрашивает, как определить, является ли файл жесткой ссылкой.
Дмитрий Григорьев
3
@DmitryGrigoryev Это довольно забавно, на самом деле, но все учатся :)
кошка

Ответы:

24

Файлы с отображением в памяти работают наоборот. Отображение памяти - это не свойство файла, а способ доступа к файлу: процесс может отобразить содержимое файла (или его подмножество) в его адресное пространство. Это облегчает чтение и запись в файл; это просто включает чтение и запись в память. Сам файл на диске такой же, как и любой другой файл.

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

Стивен Китт
источник
14
@Utku Это не имеет ничего общего с отображенными в память файлами.
Satō Katsura
12
Если вы не выключили сервер MySQL, это нормальное поведение: на сервере открыт файловый дескриптор, который остается действительным даже при mv.
Стивен Китт
11
Файловый дескриптор указывает (в конце концов) на inode в файловой системе; вот где файл действительно живет. Записи каталога также указывают на эти inode и mvпросто изменяют записи каталога, а не inode (когда он перемещает файлы в одной файловой системе).
Стивен Китт
1
Ваше описание является полезным упрощением, но только для точности: отображение памяти технически не то же самое, что файловые дескрипторы, но они работают одинаково (посредством ссылки на inode, а не на имя файла). open (), mmap (), close () не оставляет FD, только отображение, которое будет отображаться с lsof. Он не исчезнет, ​​пока процесс не вызовет munmap () или не выйдет (или не заменит отображение другим, используя mmap (MAP_FIXED) ...)
Питер Кордес
3
@Utku На самом деле вы не перемещали файл. Вы только что создали новую запись каталога, которая ссылается на тот же файл, а затем удалили старый. Изменение именования не влияет на процесс, в котором уже открыт файл.
Дэвид Шварц
11

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

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

Это может быть использовано, например , когда вы знаете , есть много доступов делать на файл, который не собирается быть последовательным, быть причиной может быть проще и эффективнее делать операции чтения и записи в память , чем проблемы read, write, и llseekсистемные звонки. Единственная проблема этого метода заключается в том, что вы не можете использовать его, если файл должен быть прочитан или записан несколькими процессами одновременно. Результаты будут непредсказуемыми.

Я не знаю команды, которая может сказать вам, если файл в настоящее время сопоставлен. Тем не менее, вы можете проверить отображение процесса в /proc/<pid>/maps(если ваша система имеет его).

Чтобы ответить на ваш второй вопрос, когда вы открываете файл, даже если вы перемещаете его в файловой системе, процессы, которые открыли его, все равно могут его использовать. Что происходит, так это то, что файл не зависит от его записей в файловых системах. Пока у вас открыт файл, у вас есть «дескриптор», дескриптор файла, который позволяет вам читать и писать в него, даже если его путь в файловой системе изменяется. Файл исчезает только тогда, когда у него нет записи в файловой системе, и ни один процесс не содержит дескриптор файла.

lgeorget
источник
Таким образом, когда мы перемещаем файл, значение дескриптора файла не изменяется. Существует отображение дескриптора пути к файлу, и изменяется только часть пути этого отображения. Это правильно?
Утку
1
В некотором смысле да, но я не уверен, что понимаю вас, поэтому позвольте мне перефразировать это. По сути, «файл» - это три вещи. Запись каталога - это путь в файловой системе. Inode - это содержимое файла. И дескриптор файла представляет собой открытый файл. И записи каталога, и дескрипторы файлов содержат указатель на их вспомогательный индекс. Когда вы открываете файл, вы передаете запись каталога, и ядро ​​возвращает вам дескриптор файла. Таким образом, даже если исходная запись каталога изменяется, дескриптор файла все еще указывает на тот же индекс, и вы можете получить доступ к файлу.
lgeorget
1
Вы можете проверить отображение процесса, хотя, в /proc/<pid>/maps. - При условии, что указанный процесс живет в системе, которая /procдолжна начинаться с. OpenBSD этого не делает, а FreeBSD постепенно его прекращает. Кроме того, FreeBSD имеет /proc/<pid>/mapвместо /proc/<pid>/maps.
Satō Katsura
@SatoKatsura Спасибо за точность. У меня под рукой только машина с Linux, поэтому я решил рассказать о своем деле и позволить людям рассказать о своем ... Не стесняйтесь редактировать ответ, если у вас есть что исправить или добавить здесь.
lgeorget
Поскольку вы спрашиваете: вы предположили, что ОП на самом деле понимает, о чем он спрашивает, и подробно объяснили, что такое отображенные в память файлы. Я не думаю, что вы сделали его услугой. ИМО ваш первый комментарий выше был гораздо более релевантным тому, о чем на самом деле спрашивал ФП, чем ваш ответ. FWIW.
Satō Katsura
9

Q4: есть команда, которая скажет, сопоставлен ли файл с памятью?

Команда lsofпокажет вам все файлы, которые в данный момент используются системой. Столбец «FD» будет содержать «mem», если файл отображен в память. Таким образом, вы можете получить выходные данные этой команды для имени файла, который вас интересует.

Wossname
источник
3
Или используйтеlsof -ad mem /path/to/file
Стефан Шазелас
5
Вернее, lsof -ad mem,txt /path/to/fileпоскольку выполняемые файлы также имеют части, отображаемые в адресном пространстве процесса, но отображаются как txtв lsofвыходных данных.
Стефан Шазелас
7

Вы, кажется, путаете отображение памяти с файлами в файловых системах, находящихся в памяти, наряду с другими понятиями, такими как то, как процессы поддерживают доступ к файлам, даже когда они перемещаются.

Я пойду вопрос за вопросом, чтобы посмотреть, смогу ли я все прояснить.

  1. Допустим, я перехожу к каталогу в моей файловой системе, и в этом каталоге есть файл. Возможно ли, чтобы этот файл указывал на область в основной памяти, а не на область на диске?

Он указывает на основную память, если она находится в файловой системе, находящейся в памяти, например, procfs, которая обычно монтируется в / proc, или sysfs, которая находится в / sys, или tmpfs, которая иногда находится в / tmp.

  1. Если это возможно, это то, что мы называем «файл с отображением в памяти»?

Нет. Как сказал Стивен-Китт, «отображение памяти» относится к способу доступа к файлу путем «сопоставления» его с основной памятью и работы с ним там, а не для чтения и записи фрагментов одновременно с помощью таких функций, как read () и записывать().

  1. Каков смысл перемещения такого файла по файловой системе (то есть перенос такого файла из одного каталога в другой)? Насколько я понимаю, поскольку файл отображен в памяти, процесс (ы), взаимодействующий с файлом, всегда записывает в предопределенную область основной памяти, и когда мы открываем этот файл (например, с помощью vim), мы читаем эту область основная память (значит, диск не задействован). Следовательно, независимо от того, куда мы перемещаем файл, он всегда будет работать правильно, верно? Если да, имеет ли какое-либо значение перемещение файла вокруг файловой системы?

Если вы перемещаете его внутри одной и той же файловой системы, вы на самом деле просто перемещаетесь по ссылке, индексу из одного каталога в другой. Если есть программы, которые уже открыли этот файл, они все равно будут обращаться к тому же файлу, потому что у них уже есть inode под дескриптором файла. Это то, что произошло с файлом table_name.idb, который вы упомянули в комментарии.

  1. Есть ли команда, которая скажет, сопоставлен ли файл с памятью?

Wossname уже ответил на это для отображенных в памяти файлов. lsofскажет вам, какие процессы отображены в памяти файла.

Чтобы узнать, находится ли файл в файловой системе, находящейся в памяти, вы можете использовать dfили mountдля вывода списка файловых систем и их точек монтирования. Вам просто нужно знать, какие типы файловых систем находятся в памяти, просматривая их (например, в википедии).

  1. Наконец, если я открою отображенный в памяти файл с помощью vim, внесу в него некоторые изменения и сохраню и закрою vim, что произойдет? Будут ли мои изменения просто записываться в основную память? Если это так, другие процессы, использующие этот файл, увидят изменения, которые я только что сделал? По моему опыту, другие процессы не видели изменений, которые я внес в файл, когда я сделал некоторые изменения в файле с помощью vim. Что является причиной этого?

Лично я не использовал эту mmapфункцию в программе на C, но, насколько я понимаю, из-за скимминга man mmapи info mmapникакой магии не требуется для поддержания представления в памяти в синхронизации. В своей основной форме вызов mmap копирует содержимое файла в память и msyncиспользуется для записи его обратно из памяти на диск. Если файл на диске изменяется, нет ничего, что могло бы обнаружить это и автоматически изменить представление в памяти во всех процессах, которые его отобразили.

РЕДАКТИРОВАТЬ: Оказывается, что mmap () на самом деле пытается синхронизировать представление в памяти при некоторых условиях. Если карта только для чтения, она будет синхронизирована, даже когда другие процессы будут записывать в файл. Если он записан (путем присвоения области памяти), то, что происходит, зависит от того, какой из явно обязательных флагов MAP_SHARED или MAP_PRIVATE предоставлен mmap (). Если указано MAP_PRIVATE, карта разветвляется из представления на диске и перестает синхронизироваться до тех пор, пока вы не используете msync (). Если предоставляется MAP_SHARED, то обновления становятся видимыми для других процессов, которым сопоставлен файл, а также (хотя это не обязательно необходимо) представление на диске.

Я просто открыл vim для существующего файла eи выполнил команду :w, inotifywait -m .запустив другой терминал. Среди некоторых странных моментов, это важная часть, которую я получил inotifywait.

./ MOVED_FROM e
./ MOVED_TO e~
./ CREATE e
./ OPEN e
./ MODIFY e
./ CLOSE_WRITE,CLOSE e
./ ATTRIB e
./ ATTRIB e
./ DELETE e~

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

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

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

Йол
источник
3
« Если файл на диске изменяется, нет ничего, что могло бы обнаружить это и автоматически изменить представление в памяти во всех процессах, которые его отобразили. » Что изменит файловую систему на диске за обратной стороной отображения операционной системы? система? Вы представляете какой-то необработанный доступ к блочному устройству или блочному устройству, совместно используемому через iSCSI, или что-то еще?
Дэвид Шварц
@ david-schwartz Нет. Я представляю два процесса с открытым файлом (). Процесс 1 использует mmap () для копирования / отображения содержимого файла в память. Затем процесс 2 использует write () (и, возможно, fsync ()) для изменения содержимого на диске. В это время процесс 1 содержимого файла в памяти не отражает изменения процесса 2, верно?
JoL
Нет, конечно нет. Назначение writeфункции - изменить данные файла. Это может означать, а может и не означать изменение содержимого на диске, но независимо от того, что оно включает, файловая система несет ответственность за его правильное выполнение. В этом случае потребуется изменить отображенную страницу памяти и пометить ее как грязную.
Дэвид Шварц
@ david-schwartz Я экспериментировал с mmap (), и ты вроде как прав. В сценарии, который я изложил в своем предыдущем комментарии, процесс содержимого 1, который имелся в памяти (на карте), действительно отражал изменения, если процесс 1 не записал в память в отображении ранее. Это было верно, даже когда процесс изменения 1 был в другом месте, чем изменение, произведенное процессом 2. Я обновил ответ, вычеркнув, что является неправильным, и добавил то, что я нашел.
JoL
1
@ david-schwartz Извините, я не хотел сказать, что mmap вел себя не так, как указано в документации, но да, я думаю, что сделал ответ слишком запутанным. Я думаю, что он все еще находится в области видимости, но вопрос «увидят ли другие процессы, которые используют этот файл, изменения, которые я только что сделал?», Кажется слишком широким. Слишком много «это зависит». Поскольку потребность в ОП кажется чисто автодидактической, я пытался дать точный ответ и охватить как можно больше оснований, но я мог бы перестараться. Впрочем, я все еще рад, что сделал это, поскольку я тоже многому научился.
JoL