Завантаження спільних бібліотек та використання оперативної пам’яті


40

Мені цікаво, як Linux управляє спільними бібліотеками. (насправді я говорю про Maemo Fremantle, дистрибутив на базі Debian, випущений в 2009 році, який працює на 256 Мб оперативної пам'яті).

Припустимо, у нас є два виконувані файли, що посилаються на libQtCore.so.4 та використовують його символи (використовуючи його класи та функції). Для простоти давайте назвемо їх aі b. Ми припускаємо, що обидва виконувані файли посилаються на одні і ті ж бібліотеки.

Спочатку ми запускаємо a. Бібліотеку потрібно завантажити. Чи завантажується вона цілою чи завантажується в пам'ять лише в тій частині, яка необхідна (оскільки ми не використовуємо кожен клас, завантажується лише код щодо використовуваних класів)?

Потім ми запускаємо b. Ми припускаємо, що aвсе ще працює. bтакож посилання на libQtCore.so.4 і використовує деякі класи, які aвикористовує, а також деякі, які не використовуються a. Чи буде бібліотека подвійно завантажена (окремо для aта окремо для b)? Або вони будуть використовувати один і той же об’єкт вже в оперативній пам'яті. Якщо bнові символи не використовуються та aвже запущені, чи збільшиться оперативна пам'ять, що використовується спільними бібліотеками? (Або різниця буде незначною)

Відповіді:


53

ПРИМІТКА. Я вважаю, що на вашому пристрої є блок відображення пам'яті (MMU). Існує версія Linux (µClinux), яка не потребує MMU, і ця відповідь там не застосовується.

Що таке MMU? Це апаратне забезпечення - частина процесора та / або контролера пам'яті. Розуміння зв’язку спільної бібліотеки не вимагає того, щоб ви точно розуміли, як працює MMU, тільки що MMU дозволяє мати різницю між адресами логічної пам'яті (тими, які використовуються програмами) та фізичнимиадреси пам'яті (ті, які є фактично на шині пам'яті). Пам'ять розбивається на сторінки, зазвичай розміром 4K в Linux. Що стосується сторінок 4k, логічні адреси 0–4095 - це сторінка 0, логічні адреси 4096–8191 - це сторінка 1 і т.д. Дана фізична сторінка може відповідати декільком логічним сторінкам (так поділяється пам'ять: кілька логічних сторінок відповідають одній фізичній сторінці). Зверніть увагу, це стосується незалежно від ОС; це опис обладнання.

Під час перемикання процесу ядро ​​змінює відображення сторінок MMU, щоб кожен процес мав власний простір. Адреса 4096 в процесі 1000 може бути (і зазвичай є) абсолютно відмінною від адреси 4096 в процесі 1001.

Практично кожен раз, коли ви бачите адресу, це логічна адреса. Програми користувальницького простору навряд чи мають справу з фізичними адресами.

Зараз існує також декілька способів створення бібліотек. Скажімо, програма викликає функцію foo()в бібліотеці. Процесор не знає нічого про символи або функціональні дзвінки насправді - він просто знає, як перейти до логічної адреси та виконати будь-який код, який він там знайде. Є кілька способів це зробити (і подібні речі застосовуються, коли бібліотека отримує доступ до власних глобальних даних тощо):

  1. Це може важко зафіксувати якусь логічну адресу, щоб зателефонувати. Це вимагає, щоб бібліотека завжди завантажувалася за точно такою ж логічною адресою. Якщо для двох бібліотек потрібна однакова адреса, динамічне посилання не вдається, і ви не можете запустити програму. Бібліотеки можуть вимагати інших бібліотек, тому в основному для кожної бібліотеки в системі є унікальні логічні адреси. Хоча це дуже швидко, якщо це працює. (Ось як робилися речі, і такий тип налаштування, який робить попереднє посилання).
  2. Це може жорстко кодувати помилкову логічну адресу та повідомити динамічний лінкер редагувати у відповідному під час завантаження бібліотеки. Це коштує небагато часу при завантаженні бібліотек, але після цього це дуже швидко.
  3. Це може додати шар непрямості: використовуйте регістр процесора, щоб утримувати логічну адресу, в яку завантажена бібліотека, а потім отримуйте доступ до всього, як зміщення цього регістра. Це накладає вартість продуктивності для кожного доступу.

Досить багато ніхто більше не використовує номер 1, принаймні, не на системах загального призначення. Утримувати цей унікальний список логічних адрес неможливо в 32-бітних системах (їх недостатньо, щоб обійти) та адміністративному кошмарі в 64-бітних системах. Це попереднє зв’язування робить це, однак, за системою.

Використовуватиметься №2 або №3, залежить від того, чи була створена бібліотека за допомогою параметра GCC -fPIC(незалежний від позиції код). №2 - без, # 3 - з. Як правило, бібліотеки побудовані за допомогою -fPIC, тому №3 - це те, що відбувається.

Докладніше див. У статті " Як писати спільні бібліотеки" (PDF) Ulrich Drepper .

Отже, нарешті, на ваше запитання можна відповісти:

  1. Якщо бібліотека побудована з -fPIC (як це майже напевно повинно бути), то переважна більшість сторінок точно такі ж, як і для кожного процесу, що її завантажує. Ваші процеси aі bможуть завантажувати бібліотеку за різними логічними адресами, але ті вказуватимуть на ті самі фізичні сторінки: пам'ять буде спільною. Крім того, дані в оперативній пам’яті точно відповідають тому, що є на диску, тому вони можуть завантажуватися лише за потреби обробника помилок сторінки.
  2. Якщо бібліотека побудована без -fPIC , то виявиться, що для більшості сторінок бібліотеки знадобиться редагування посилань, і вони будуть іншими. Тому вони повинні бути окремими фізичними сторінками (оскільки вони містять різні дані). Це означає, що їх не поділяють. Сторінки не відповідають тому, що є на диску, тому я не здивуюся, якщо буде завантажена вся бібліотека. Звичайно, згодом це можна буде замінити на диск (у свопфілі).

Ви можете перевірити це за допомогою pmapінструменту або безпосередньо, перевіривши різні файли в /proc. Наприклад, ось (частковий) вихід pmap -xдвох різних щойно породжених bcs. Зауважте, що адреси, показані 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) видно, що весь сегмент бібліотеки не завантажений. Нарешті, ви бачите, що для більш великих відображень брудне значення дорівнює 0, тобто точно відповідає тому, що є на диску.

Ви можете повторно запустити pmap -XX, і це покаже вам - залежно від версії ядра, яку ви працюєте, оскільки вихід -XX залежить від версії ядра, що перше відображення має Shared_Clean176, що точно відповідає рівню RSS. SharedПам'ять означає, що фізичні сторінки діляться між декількома процесами, і оскільки вони відповідають RSS, це означає, що вся бібліотека, що знаходиться в пам'яті, є спільною (див. Див. також див. нижче для подальшого пояснення спільного та приватного):

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


Дивитися також


Це означає, що передпосилання вже не має жодної користі (і -fPICвикористання цього часу повністю змінилося)?
Hauke ​​Laging

@crisron Дякую за виправлення. FYI, Markdown вважатиме за тебе - виведений результат мого повторення 1. був правильним. Крім того, я вніс декілька змін у те, що ви зробили - "початкова адреса" - це технічний жаргон, я, ймовірно, викликав плутанину, поставивши "логічний" посередині. Я змінив це, щоб позбутися жаргону. Крім того, сторінки еквівалентні цим адресам, AFAIK неможливо, щоб ці адреси колись були іншою сторінкою. Я спробував ще раз, поміняючи замовлення, сподіваюся, це зрозуміліше.
дероберт

чорт, зараз це відповідь !!!
Еван Керролл
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.