Ядро Linux/Пам'ять

Матеріал з Вікіпідручника

Вступ[ред.]

Ядро має повний доступ до пам'яті системи і повинне дозволити процесам безпечно доступатися до цієї пам'яті при необхідності. Часто першим кроком у реалізації його є віртуальна адресація (англ. virtual addressing), що як правило здійснюється за допомогою сторінок і/або сегментації. Віртуальна адресація дозволяє зробити так, що дана фізична адреса пам'яті матиме ішу віртуальну адресу. Простори віртуальних адрес можуть бути різними для різних процесів; пам'ять до якої доступається один процес за певною (віртуальною) адресою тоді може бути іншою областю пам'яті, ніж коли інший процес доступається до цієї самої віртуальної адреси. Це дозволяє програмі виконуватися так, не знаючи ні про виконання ядра ні інших процесів, ьак ніби вона виконується сама, таким чином запобігаючи виникненню колізій між застосуваннями.

У багатьох системах, віртуальна адреса програми може посилатися на дані, які на даний момент не знаходяться у пам'яті. Шар перенаправлення, що забезпечує віртуальна адресація, дозволяє операційній системі викристовувати інші сховища даних, наприклад жорсткий диск, щоб зберігати те, що постійно мало лишатися в основній пам'яті (RAM). В результаті, операційна система може використовувати більше пам'яті ніж її фізично доступно в операційній системі. Якщо програма потребує отримати дані, які зараз не присутні у RAM, CPU передає сигнал ядру про те, що таке відбулося і ядро відповідає на нього записуючи вміст неактивного блоку пам'яті на диск (щоб звільнити місце якщо це необхідно) і заміняє його на данія, які запросила програма. Після чого програма може продовжити виконання з того місця де вона була зупинена. Ця схема як правило називається англ. demand paging.

Віртуальна адресація також дозволяє створювати віртуальні розділи пам'яті і створювати дві роздільні області, одна з яких буде віддана ядру (область ядра) а інша буде віддана застосуванням (користувацький простір). Процесор не дозволяє застосуванням звертатися до адрес пам'яті ядра, таким чином не дозволяє застосуванню зруйнувати область пам'яті працюючого ядра. Це фундаментальне розділення простору пам'яті зробило великий внесок до сучасного проектування ядр систем загального призначення і є майже універасльним в таких системах, Linux є однією з них.

Структура пам'яті процесу[ред.]

32-бітний процесор може адресувати максимально 4GB пам'яті. Linux розділяє адресний простір розміром в 4GB між процесами користувача і ядром; у типовій конфігурації, перші 3GB 32-бітного діапазону адрес віддані користувацькому простору, а ядро отримує останній 1GB пам'яті починаючи з адреси 0xc0000000. Спільний доступ до адресного простору дає декілька переваг в продуктивності; зокрема, адреса буферу куди відбувається запис даних з обладнання може бути спільною між ядром і кристувацьким застосуванням.

В x86-64, лише найменші значимі 48 біт адреси віртуальної пам'яті фактично використовуються для перетворення адреси (пошуку по таблиці сторінок). Решта біт від 48 до 63 для будь-якої віртуальної адреси повинні бути копією біта 47, або процесор згенерує виключну ситуацію. Формат адрес що відповідають цьому правилу називають "канонічною формою." Адреси канонічної форми приймають значення від 0 до 00007FFF'FFFFFFFF, і від FFFF8000'00000000 до FFFFFFFF'FFFFFFFF, для загального об'єму в 256 TB доступного для використання віртуального адресного простору. Це приблизно в 64000 разів більше від вірутального адресного простору в 32-бітних машинах.

Linux забирає половину із вищіми значеннями адресів адресного простору для власних потреб (простір ядра) і залишає половину із меншими значеннями адресів для користувацького простору. Цей принцип "канонічного адресу" має, по суті, утворює дві половини пам'яті: нижня частина починається з 00000000'00000000 і далі дареси збільшуються вгору з тим як більше бітів віртуальної адреси стає доступними, в той час як вища частина "прилягає" до гори адресного простору і поширюється до низу до менших значень адреси.

Структура пам'яті x86-64
Структура пам'яті x86-64

Алокація пам'яті в ядрі[ред.]

kmalloc()[ред.]

kmalloc() є стандартним методом для виділення пам'яті в ядрі для об'єктів, що потребують об'єму, який менший за розмір сторінки пам'яті. Він визначений у файлу заголовка include/linux/slab.h:

#include <linux/slab.h>

void *kmalloc(size_t size, int flags);

Першим аргументом методу є size, що визначає розмір (в байтах) блоку пам'яті, який буде виділено. Другий аргумент flags визначає флаги для алокатора або GFP flags, набір визначених за допомогою макроса значень, що дозволяють встановлювати тип необхідної пам'яті. Найчастішими значеннями для параметру flags є GFP_KERNEL або GFP_ATOMIC, але існує ширший набір опцій.