Чи створює malloc ліниво допоміжні сторінки для розподілу на Linux (та інших платформах)?


75

Якби я malloc(1024 * 1024 * 1024)працював у Linux , що насправді робить malloc?

Я впевнений, що він призначає віртуальну адресу виділенню (проходячи безкоштовний список і створюючи нове відображення, якщо це необхідно), але чи насправді це створює сторінки обміну на 1 ГіБ? Або це mprotectдіапазон адрес і створює сторінки, коли ви насправді торкаєтесь їх, як mmapце робить?

(Я вказую Linux, оскільки стандарт мовчить щодо таких деталей, але мені було б цікаво знати, що роблять і інші платформи.)


2
Цікаве питання; Мені було б цікаво поведінкою на інших платформах, але похвала за те, що я запитав це питання до Linux.
Пол Соньє,

Був час, коли це здавалося багато пам’яті ...
След

Відповіді:


43

Linux виконує відкладене виділення сторінок, ака. "оптимістичне розподіл пам'яті". Пам'ять, яку ви отримуєте від malloc, нічим не підкріплена, і коли ви доторкнетесь до неї, ви можете насправді отримати умову OOM (якщо для сторінки, яку ви вимагаєте, немає місця підкачки), і в цьому випадку процес безцеремонно припиняється .

Див., Наприклад, http://www.linuxdevcenter.com/pub/a/linux/2006/11/30/linux-out-of-memory.html


5
Цікаво спостерігати за тим, як ядро ​​обчислює "поганість" процесу, щоб з'ясувати, які процеси вбити, коли закінчується пам'ять.
JesperE

IIRC має рівні: від найвищого до найнижчого - кореневі процеси, процеси, що виконують введення-виведення, сплячі процеси ... найнижчі отримують кулю.
Aiden Bell

@Aiden Функція "поганої поведінки", яка використовується для визначення процесу вбивства, описана у посиланні.
Аарон Маенпаа,

1
Пізня поведінка OOM не завжди відповідає дійсності; це залежить від налаштування надмірності. Дивіться kernel.org/doc/Documentation/vm/overcommit-accounting для трьох режимів.
ZachB

16

9. Пам'ять (частина ядра Linux , Деякі зауваження щодо ядра Linux від Andries Brouwer) - хороший документ.

Він містить наступні програми, які демонструють обробку Linux фізичною пам’яттю проти фактичної пам’яті та пояснює внутрішні елементи ядра.

Як правило, перша демонстраційна програма отримає дуже великий обсяг пам'яті, перш ніж malloc () поверне NULL. Друга демонстраційна програма отримає набагато менший обсяг пам'яті, тепер, коли раніше отримана пам’ять фактично використовується. Третя програма отримає таку ж велику кількість, як і перша програма, а потім її вбивають, коли вона хоче використовувати свою пам’ять.

Демо-програма 1: виділити пам’ять, не використовуючи її.

Демо-програма 2: виділіть пам’ять і насправді торкніться її всієї.

Демо-програма 3: спочатку розподіліть і використовуйте пізніше.

(У добре функціонуючій системі, як Solaris , три демонстраційні програми отримують однакову кількість пам'яті і не виходять з ладу, але бачать, що malloc () повертає NULL.)


6
"добре функціонувати" - це питання думки. Насправді Linux має опції в / proc / sys / vm для управління поведінкою надмірних зобов'язань. Ви можете мати його як Solaris, якщо хочете.
Zan Lynx

2
Будьте застережені, / proc / sys / vm Зламаний більшу частину часу !! groups.google.com/group/comp.os.linux.development.system/… Ось ДОБРА ПОРАДА ДЛЯ ВИСТАВКИ LINUX І ДИСКА. Якщо ви коли-небудь робите велику копію, і багато кеш-пам’яті звикає, і ваша система вводу-виводу починає заглиблюватися .... echo 1> / proc / sys / vm / drop_caches висока пропускна здатність :) іди малюнок !!
RandomNickName42

11

Я дав цю відповідь у подібному дописі на ту ж тему:

Деякі розподільники ледачі?

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

Повертаючись до вашого запитання, ідея схожа. Як зазначали інші, запит на пам’ять негайно отримує простір віртуальної пам’яті, але фактичні сторінки виділяються лише при записі на них.

Яка мета цього? В основному це робить помилки з пам'яті більш-менш постійною операцією часу Big O (1) замість операції Big O (n) (подібно до того, як планувальник Linux поширює свою роботу, замість того, щоб робити це одним великим шматком).

Щоб продемонструвати, що я маю на увазі, я провів наступний експеримент:

rbarnes@rbarnes-desktop:~/test_code$ time ./bigmalloc

real    0m0.005s
user    0m0.000s
sys 0m0.004s
rbarnes@rbarnes-desktop:~/test_code$ time ./deadbeef

real    0m0.558s
user    0m0.000s
sys 0m0.492s
rbarnes@rbarnes-desktop:~/test_code$ time ./justwrites

real    0m0.006s
user    0m0.000s
sys 0m0.008s

Програма bigmalloc виділяє 20 мільйонів інтів, але нічого з ними не робить. deadbeef записує по одному int на кожну сторінку, в результаті чого 19531 пише і justwrites виділяє 19531 ints і обнуляє їх. Як бачите, виконувальна робота займає приблизно в 100 разів більше часу, ніж bigmalloc, і приблизно в 50 разів довша, ніж просто написання.

.

.


6

Malloc виділяє пам’ять із блоків, якими керує libc. Коли потрібна додаткова пам'ять, бібліотека надходить до ядра за допомогою системного виклику brk.

Ядро виділяє сторінки віртуальної пам'яті для процесу виклику. Сторінками керується як частина ресурсів, якими володіє процес. Фізичні сторінки не виділяються, коли пам'ять brk'd. Коли процес звертається до будь-якого місця пам'яті на одній зі сторінок brk'd, виникає помилка сторінки. Ядро перевіряє, що віртуальна пам'ять була виділена, і переходить до відображення фізичної сторінки до віртуальної сторінки.

Розподіл сторінок не обмежується записами і цілком відрізняється від копіювання під час запису. Будь-який доступ, читання або запис призводить до помилки сторінки та відображення фізичної сторінки.

Зверніть увагу, що пам’ять стека автоматично відображається. Тобто явного brk не потрібно для відображення сторінок у віртуальній пам’яті, яка використовується стеком.


Зауважте, що glibc виконує великі розподіли, створюючи анонімні сторінки замість brk. Див. Gnu.org/software/libc/manual/html_node/The-GNU-Allocator.html .
ZachB

5

У Windows сторінки зафіксовано (тобто вільна пам’ять зменшується), але вони фактично не будуть розподілятися, доки ви не торкнетесь сторінок (або прочитати, або записати).


2

У більшості Unix-подібних систем він управляє межею brk . Віртуальна машина додає сторінки при попаданні процесора. Принаймні це роблять Linux і BSD .

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