Я часто сталкиваюсь с ситуацией при разработке, когда я запускаю двоичный файл, скажем, a.out
в фоновом режиме, поскольку он выполняет какую-то длительную работу. Пока я это делаю, я делаю изменения в коде C, который производит a.out
и компилирует a.out
снова. До сих пор у меня не было никаких проблем с этим. Процесс, который выполняется, a.out
продолжается как обычно, никогда не завершается сбоем и всегда запускает старый код, с которого он изначально был запущен.
Тем не менее, скажем, a.out
был огромный файл, возможно, сравнимый с размером оперативной памяти. Что будет в этом случае? И скажите, что это связано с общим объектным файлом libblas.so
, что, если я изменил libblas.so
во время выполнения? Что случилось бы?
Мой главный вопрос - гарантирует ли ОС, что при запуске a.out
исходный код всегда будет работать нормально, в соответствии с исходным двоичным .so
файлом , независимо от размера двоичного файла или файлов, на которые он ссылается, даже если эти файлы .o
и .so
файлы были изменены во время во время выполнения?
Я знаю, что есть эти вопросы, которые касаются подобных проблем: /programming/8506865/when-a-binary-file-runs-does-it-copy-its-entire-binary-data-into-memory -при однократный Что происходит при редактировании сценария во время выполнения? Как сделать живое обновление во время работы программы?
Что помогло мне понять немного больше об этом, но я не думаю, что они спрашивают, что именно я хочу, что является общим правилом для последствий изменения двоичного файла во время выполнения
if they are read-only copies of something already on disc (like an executable, or a shared object file), they just get de-allocated and are reloaded from their source
, поэтому у меня сложилось впечатление, что если ваш двоичный файл огромен, то если часть вашего двоичного файла выходит из ОЗУ, но затем требуется снова, он «перезагружается из источника» - поэтому любые изменения в.(s)o
файл будет отражен во время выполнения. Но, конечно, я, возможно, неправильно понял - вот почему яNo, it only loads the necessary pages into memory. This is demand paging.
, что у меня сложилось впечатление, что то, что я просил, не может быть гарантировано.Ответы:
Хотя вопроса о переполнении стека сначала было достаточно, я понимаю из ваших комментариев, почему у вас все еще могут возникнуть сомнения по этому поводу. Для меня это как раз та критическая ситуация , которая возникает, когда две подсистемы UNIX (процессы и файлы) обмениваются данными.
Как вы, возможно, знаете, системы UNIX обычно делятся на две подсистемы: файловую подсистему и подсистему процессов. Теперь, если в системном вызове не указано иное, ядро не должно взаимодействовать между этими двумя подсистемами. Однако есть одно исключение: загрузка исполняемого файла в текстовые области процесса . Конечно, можно утверждать, что эта операция также запускается системным вызовом (
execve
), но обычно известно, что это тот случай, когда подсистема процесса делает неявный запрос к файловой подсистеме.Поскольку у подсистемы процессов, естественно, нет способа обработки файлов (иначе не было бы смысла делить все это на две части), она должна использовать все, что файловая подсистема предоставляет для доступа к файлам. Это также означает, что подсистема процесса подчиняется любым мерам, которые файловая подсистема принимает в отношении редактирования / удаления файла. На данный момент, я рекомендую прочитать ответ Жиля на этот U & L вопрос . Остальная часть моего ответа основана на более общем ответе Жиля.
Первое, что следует отметить, это то, что внутренне файлы доступны только через inode . Если ядру дан путь, его первым шагом будет преобразование его в inode, который будет использоваться для всех других операций. Когда процесс загружает исполняемый файл в память, он делает это через свой инод, который был предоставлен файловой подсистемой после преобразования пути. Иноды могут быть связаны с несколькими путями (ссылками), а программы могут удалять только ссылки. Чтобы удалить файл и его индекс, пользовательская область должна удалить все существующие ссылки на этот индекс и убедиться, что он полностью не используется. Когда эти условия будут выполнены, ядро автоматически удалит файл с диска.
Если вы посмотрите на заменяющую исполняемую часть ответа Жиля, вы увидите, что в зависимости от того, как вы редактируете / удаляете файл, ядро будет реагировать / адаптироваться по-разному, всегда через механизм, реализованный в файловой подсистеме.
ETXTBSY
). Никаких последствий.mv
операция атомарная. Это, вероятно, потребует использованияrename
системного вызова, и, поскольку процессы не могут быть прерваны в режиме ядра, ничто не может помешать этой операции, пока она не завершится (успешно или нет). Опять же, никакого изменения inode старого файла не происходит: создается новый, и уже запущенные процессы не будут знать об этом, даже если он связан с одной из ссылок старого inode.Перекомпиляция файла : при использовании
gcc
(и поведение, вероятно, аналогичное для многих других компиляторов), вы используете стратегию 2. Это можно увидеть, запустивstrace
процессы вашего компилятора:stat
иlstat
системные вызовы.a.out
, его индекс и содержимое остаются на диске до тех пор, пока они используются уже запущенными процессами.a.out
. Это совершенно новый инод и совершенно новое содержимое, о котором уже не заботятся уже запущенные процессы.Теперь, когда дело доходит до разделяемых библиотек, применяется то же самое поведение. Пока объект библиотеки используется процессом, он не будет удален с диска, независимо от того, как вы измените его ссылки. Всякий раз, когда что-то должно быть загружено в память, ядро будет делать это через inode файла и, следовательно, будет игнорировать изменения, внесенные вами в его ссылки (например, связать их с новыми файлами).
источник
df
количества свободных байтов на диске с использованием неправильного метода, так как он не принимает иноды, которые все ссылки на файловые системы удалены? Так я должен использоватьdf -i
? (Это просто техническое любопытство, мне не нужно точно знать точное использование диска!)rm
илиmv
его как inode в исходный файл не удаляете, пока все процессы не удалят свою ссылку на этот inode.df
включенный) не может получить информацию об индексе. Какую бы новую информацию вы не нашли, она связана с новым файлом и новым индексом. Основной момент здесь заключается в том, что подсистема процессов не заинтересована в этой проблеме, поэтому понятия управления памятью (подкачки по требованию, подкачки процессов, сбоев страниц и т. Д.) Совершенно неактуальны. Это проблема файловой подсистемы, и она решается файловой подсистемой. Подсистема процессов не беспокоится об этом, это не то, для чего она здесь.df -i
: этот инструмент, вероятно, извлекает информацию из суперблока fs или его кэша, что означает, что он может включать в себя inode старого двоичного файла (для которого все ссылки были удалены). Это не означает, что новые процессы могут свободно использовать эти старые данные.Насколько я понимаю, из-за сопоставления памяти запущенного процесса ядро не позволит обновить зарезервированную часть сопоставленного файла. Я предполагаю, что если процесс запущен, то весь его файл зарезервирован, следовательно, его обновление, потому что вы скомпилировали новую версию своего исходного кода, фактически приводит к созданию нового набора inode. Короче говоря, старые версии вашего исполняемого файла остаются доступными на диске через события сбоя страницы. Так что даже если вы обновляете огромный файл, он должен оставаться доступным и ядро должно еще увидеть нетронутую версию до тех пор , пока процесс запущен. Исходные файловые индексы не должны использоваться повторно до тех пор, пока выполняется процесс.
Это, конечно, должно быть подтверждено.
источник
Это не всегда так при замене файла .jar. Ресурсы Jar и некоторые загрузчики классов отражения времени выполнения не читаются с диска, пока программа явно не запросит информацию.
Это только проблема, потому что jar - это просто архив, а не отдельный исполняемый файл, который отображается в памяти. Это немного неестественно, но все еще является ответом на ваш вопрос и кое-чем, с чем я выстрелил себе в ногу.
Так что для исполняемых файлов: да. Для файлов JAR: возможно (в зависимости от реализации).
источник