ПРИМЕЧАНИЕ. Я предполагаю, что на вашем компьютере есть блок отображения памяти (MMU). Существует версия Linux (µClinux), для которой не требуется MMU, и этот ответ к ней неприменим.
Что такое MMU? Это аппаратное обеспечение - часть процессора и / или контроллера памяти. Понимание связывания разделяемых библиотек не требует от вас точного понимания того, как работает MMU, просто MMU позволяет иметь различие между логическими адресами памяти (теми, которые используются программами) и физическими адреса памяти (реально присутствующие на шине памяти). Память разбита на страницы, обычно размером 4K в Linux. Для страниц 4k логические адреса 0–4095 - это страница 0, логические адреса 4096–8191 - страница 1 и т. Д. MMU отображает их на физические страницы RAM, и каждая логическая страница обычно может быть сопоставлена с 0 или 1 физическими страницами.Данная физическая страница может соответствовать нескольким логическим страницам (так распределяется память: несколько логических страниц соответствуют одной и той же физической странице). Обратите внимание, что это применимо независимо от ОС; это описание оборудования.
При переключении процесса ядро изменяет отображение страниц MMU, так что каждый процесс имеет собственное пространство. Адрес 4096 в процессе 1000 может (и обычно так) полностью отличаться от адреса 4096 в процессе 1001.
Практически всякий раз, когда вы видите адрес, это логический адрес. Программы пользовательского пространства почти никогда не имеют дело с физическими адресами.
Теперь есть несколько способов создания библиотек. Допустим, программа вызывает функцию foo ()
в библиотеке. ЦП на самом деле ничего не знает о символах или вызовах функций - он просто знает, как перейти к логическому адресу и выполнить любой найденный там код. Есть несколько способов сделать это (и аналогичные вещи применимы, когда библиотека обращается к своим собственным глобальным данным и т. Д.):
Практически никто больше не использует №1, по крайней мере, в системах общего назначения. Сохранение этого уникального логического списка адресов невозможно в 32-битных системах (их недостаточно), а в 64-битных системах это кошмар для администрирования. Однако предварительное связывание делает это для каждой системы.
Используется ли №2 или №3, зависит от того, была ли библиотека построена с опцией GCC -fPIC
(независимый от позиции код). №2 без, №3 с. Обычно библиотеки создаются с помощью -fPIC
, поэтому происходит №3.
Подробнее см. Ульрих Дреппер Как писать общие библиотеки (PDF) .
Итак, наконец, на ваш вопрос можно ответить:
-fPIC
(как это почти наверняка должно быть), то подавляющее большинство страниц точно соответствуют то же самое для каждого процесса, который его загружает. Ваши процессы a
и b
вполне могут загружать библиотеку по разным логическим адресам, но они будут указывать на одни и те же физические страницы: память будет совместно использоваться.Кроме того, данные в ОЗУ точно соответствуют тому, что находится на диске, поэтому они могут быть загружены только при необходимости обработчику ошибок страницы. -fPIC
, то оказывается, что большинство страниц библиотеки потребуют редактирования ссылок, и они будут другими. Следовательно, они должны быть отдельными физическими страницами (поскольку они содержат разные данные). Это означает, что они не разделяются. Страницы не соответствуют тому, что находится на диске,поэтому я не удивлюсь, если будет загружена вся библиотека. Конечно, впоследствии его можно выгрузить на диск (в файле подкачки). Вы можете проверить это с помощью инструмента pmap
или напрямую, проверив различные файлы в / proc
. Например, вот (частичный) вывод pmap -x
на двух разных вновь созданных bc
s. Обратите внимание, что адреса, показанные pmap, как правило, являются логическими адресами:
pmap -x 14739
Address Kbytes RSS Dirty Mode Mapping
00007f81803ac000 244 176 0 r-x-- libreadline.so.6.2
00007f81803e9000 2048 0 0 ----- libreadline.so.6.2
00007f81805e9000 8 8 8 r---- libreadline.so.6.2
00007f81805eb000 24 24 24 rw--- libreadline.so.6.2
pmap -x 17739
Address Kbytes RSS Dirty Mode Mapping
00007f784dc77000 244 176 0 r-x-- libreadline.so.6.2
00007f784dcb4000 2048 0 0 ----- libreadline.so.6.2
00007f784deb4000 8 8 8 r---- libreadline.so.6.2
00007f784deb6000 24 24 24 rw--- libreadline.so.6.2
Вы можете видеть, что библиотека загружается несколькими частями, а pmap -x
дает подробную информацию по каждой отдельно. Вы заметите, что логические адреса этих двух процессов различаются; разумно ожидать, что они будут одинаковыми (поскольку работает одна и та же программа, и компьютеры обычно предсказуемы), но есть функция безопасности, называемая рандомизацией разметки адресного пространства , которая намеренно рандомизирует их.
По разнице в размере (килобайтах) и резидентном размере (RSS) видно, что не был загружен весь сегмент библиотеки. Наконец, вы можете видеть, что для более крупных сопоставлений значение dirty равно 0, что означает, что оно точно соответствует тому, что находится на диске.
Вы можете повторно запустить pmap -XX
, и он покажет вам - в зависимости от версии ядра, которую вы используете, поскольку вывод -XX зависит от версии ядра, - что первое сопоставление имеет a Shared_Clean
из 176, что точно соответствует RSS
. Совместно используемая
память означает, что физические страницы используются совместно несколькими процессами, и, поскольку он соответствует RSS, это означает, что вся библиотека, находящаяся в памяти, является общей (см. Также см. Ниже для дальнейшего объяснения совместной и . private):
pmap -XX 17739
Address Perm Offset Device Inode Size Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous AnonHugePages Swap KernelPageSize MMUPageSize Locked VmFlagsMapping
7f784dc77000 r-xp 00000000 fd:00 1837043 244 176 19 176 0 0 0 176 0 0 0 4 4 0 rd ex mr mw me sd libreadline.so.6.2
7f784dcb4000 ---p 0003d000 fd:00 1837043 2048 0 0 0 0 0 0 0 0 0 0 4 4 0 mr mw me sd libreadline.so.6.2
7f784deb4000 r--p 0003d000 fd:00 1837043 8 8 8 0 0 0 8 8 8 0 0 4 4 0 rd mr mw me ac sd libreadline.so.6.2
7f784deb6000 rw-p 0003f000 fd:00 1837043 24 24 24 0 0 0 24 24 24 0 0 4 4 0 rd wr mr mw me ac sd libreadline.so.6.2
См. также
Есть ли символическая ссылка /Volumes/Mac_Storage/pdf2txt/pdf2txt
, указывающая на .
?
Запустите ls -l /Volumes/Mac_Storage/pdf2txt
для проверки.
Если вы видите такую строку:
lrwxrwxrwx 1 madmiddle madmiddle 1 Feb 12 12:34 pdf2txt ->.
...тогда причина в этом.
Команда для создания такой ссылки будет ln -s. pdf2txt
, что довольно легко может произойти случайно в результате опечатки.
Я думаю, что ответ telcoM обнюхивает первопричину :Скорее всего, это связано с символической ссылкой, просто другой.
Основываясь на моих экспериментах, есть один набор обстоятельств, который отвечает всем требованиям:
Test_folder
— символическая ссылка на pdf2txt
,и cp
, унаследованную от BSD Этот тип символической ссылки нарушает обнаружение циклов macOS cp
. (GNU cp
, который был бы установлен Homebrew или каким-либо другим менеджером пакетов, по умолчанию не использует символические ссылки, даже при рекурсивном копировании.)
Вот демонстрация, проверенная на macOS High Sierra:
$ ln -s pdf2txt Test_folder
$ ls -lAF Test_folder
lrwxr-xr-x 1 aho staff 7 Feb 13 20:13 Test_folder -> pdf2txt/
$ /bin/cp -r pdf2txt Test_folder
cp: Test_folder/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt: name too long (not copied)
cp: Test_folder/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt: name too long (not copied)
# Let's just look at the first 30 lines of a recursive ls
# (And yes, we're looking at pdf2txt)
$ ls -lRAF pdf2txt | head -n 30
pdf2txt:
total 0
drwxr-xr-x+ 5 aho staff 170 Feb 13 20:13 pdf2txt/
-rw-r--r--+ 1 aho staff 0 Feb 13 19:43 test1.txt
-rw-r--r--+ 1 aho staff 0 Feb 13 19:43 test2.txt
pdf2txt/pdf2txt:
total 0
drwxr-xr-x+ 3 aho staff 102 Feb 13 20:13 pdf2txt/
-rw-r--r--+ 1 aho staff 0 Feb 13 20:13 test1.txt
-rw-r--r--+ 1 aho staff 0 Feb 13 20:13 test2.txt
pdf2txt/pdf2txt/pdf2txt:
total 0
drwxr-xr-x+ 3 aho staff 102 Feb 13 20:13 pdf2txt/
pdf2txt/pdf2txt/pdf2txt/pdf2txt:
total 0
drwxr-xr-x+ 3 aho staff 102 Feb 13 20:13 pdf2txt/
pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt:
total 0
drwxr-xr-x+ 3 aho staff 102 Feb 13 20:13 pdf2txt/
pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt:
total 0
drwxr-xr-x+ 3 aho staff 102 Feb 13 20:13 pdf2txt/
pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt/pdf2txt:
total 0