Распределение памяти приятеля - Buddy memory allocation
В распределение памяти приятеля техника это выделение памяти алгоритм, который делит память на разделы, чтобы попытаться удовлетворить запрос памяти как можно более подходящим образом. Эта система использует разделение памяти на половинки, чтобы попытаться подобрать наилучшее соответствие. В соответствии с Дональд Кнут, система друзей была изобретена в 1963 г. Гарри Марковиц, и впервые был описан Кеннет С. Ноултон (опубликовано в 1965 г.).[1] Распределение памяти Buddy относительно легко реализовать. Он поддерживает ограниченное, но эффективное разделение и объединение блоков памяти.
Алгоритм
Существуют различные формы приятельской системы; те, в которых каждый блок разделен на два меньших блока, являются самой простой и наиболее распространенной разновидностью. Каждый блок памяти в этой системе имеет порядок, где порядок - целое число от 0 до указанного верхнего предела. Размер блока порядка n пропорционален 2п, так что блоки ровно в два раза больше блоков, которые на порядок меньше. Размеры блоков, равные степени двойки, упрощают вычисление адресов, поскольку все партнеры выровнены по границам адресов памяти, которые являются степенью двойки. Когда большой блок разбивается, он делится на два меньших блока, и каждый меньший блок становится уникальным другом для другого. Разделенный блок можно объединить только с его уникальным партнерским блоком, который затем преобразует более крупный блок, из которого они были отделены.
Вначале определяется размер наименьшего возможного блока, то есть наименьшего блока памяти, который может быть выделен. Если бы вообще не существовало нижнего предела (например, было бы возможно распределение размера в битах), для системы было бы много памяти и вычислительных затрат, чтобы отслеживать, какие части памяти выделены и нераспределены. Однако может быть желателен довольно низкий предел, чтобы свести к минимуму средние потери памяти на выделение (в отношении выделений, которые по размеру не кратны наименьшему блоку). Обычно нижний предел будет достаточно малым, чтобы свести к минимуму среднее потраченное впустую пространство на выделение, но достаточно большим, чтобы избежать чрезмерных накладных расходов. Наименьший размер блока затем принимается за размер блока нулевого порядка, так что все более высокие порядки выражаются в виде кратных степени двух этого размера.
Затем программист должен решить или написать код для получения максимально возможного порядка, который может уместиться в оставшемся доступном пространстве памяти. Поскольку общая доступная память в данной компьютерной системе может не быть кратной минимальному размеру блока в степени двойки, наибольший размер блока может не охватывать всю память системы. Например, если в системе было 2000 КБ физической памяти и размер блока нулевого порядка был 4 КБ, верхний предел порядка был бы 8, поскольку блок порядка 8 (256 блоков нулевого порядка, 1024 КБ) равен самый большой блок, который уместится в памяти. Следовательно, невозможно выделить всю физическую память в одном фрагменте; оставшиеся 976 КБ памяти должны быть выделены меньшими блоками.
Пример
Ниже приводится пример того, что происходит, когда программа запрашивает память. Скажем, в этой системе минимально возможный блок имеет размер 64 килобайта, а верхний предел для порядка равен 4, что приводит к максимально возможному размещаемому блоку, 24 умножить на 64 K = 1024 K. Ниже показано возможное состояние системы после различных запросов к памяти.
Шаг | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К | 64 К |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 24 | |||||||||||||||
2.1 | 23 | 23 | ||||||||||||||
2.2 | 22 | 22 | 23 | |||||||||||||
2.3 | 21 | 21 | 22 | 23 | ||||||||||||
2.4 | 20 | 20 | 21 | 22 | 23 | |||||||||||
2.5 | А: 20 | 20 | 21 | 22 | 23 | |||||||||||
3 | А: 20 | 20 | БИ 21 | 22 | 23 | |||||||||||
4 | А: 20 | С: 20 | БИ 21 | 22 | 23 | |||||||||||
5.1 | А: 20 | С: 20 | БИ 21 | 21 | 21 | 23 | ||||||||||
5.2 | А: 20 | С: 20 | БИ 21 | Д: 21 | 21 | 23 | ||||||||||
6 | А: 20 | С: 20 | 21 | Д: 21 | 21 | 23 | ||||||||||
7.1 | А: 20 | С: 20 | 21 | 21 | 21 | 23 | ||||||||||
7.2 | А: 20 | С: 20 | 21 | 22 | 23 | |||||||||||
8 | 20 | С: 20 | 21 | 22 | 23 | |||||||||||
9.1 | 20 | 20 | 21 | 22 | 23 | |||||||||||
9.2 | 21 | 21 | 22 | 23 | ||||||||||||
9.3 | 22 | 22 | 23 | |||||||||||||
9.4 | 23 | 23 | ||||||||||||||
9.5 | 24 |
Это распределение могло произойти следующим образом
- Исходная ситуация.
- Программа A запрашивает память 34 КБ, порядок 0.
- Блоки порядка 0 недоступны, поэтому блок порядка 4 разделяется, создавая два блока порядка 3.
- По-прежнему нет доступных блоков порядка 0, поэтому блок первого порядка 3 разделяется, создавая два блока порядка 2.
- По-прежнему нет доступных блоков порядка 0, поэтому блок первого порядка 2 разделяется, создавая два блока порядка 1.
- По-прежнему нет доступных блоков порядка 0, поэтому первый блок порядка 1 разделяется, создавая два блока порядка 0.
- Теперь доступен блок порядка 0, поэтому он назначен A.
- Программа B запрашивает память 66 КБ, порядок 1. Доступен блок порядка 1, поэтому он выделяется B.
- Программа C запрашивает память 35 КБ, порядок 0. Доступен блок порядка 0, поэтому он выделяется C.
- Программа D запрашивает память 67 КБ, порядок 1.
- Блоки порядка 1 недоступны, поэтому блок порядка 2 разделяется, создавая два блока порядка 1.
- Теперь доступен блок порядка 1, поэтому он назначен D.
- Программа B освобождает свою память, освобождая один блок порядка 1.
- Программа D освобождает свою память.
- Освобождается один блок порядка 1.
- Так как партнерский блок только что освобожденного блока также является свободным, эти два объединяются в один блок порядка 2.
- Программа A освобождает свою память, освобождая один блок порядка 0.
- Программа C освобождает свою память.
- Освобождается один блок порядка 0.
- Так как партнерский блок только что освобожденного блока также является свободным, эти два объединяются в один блок порядка 1.
- Поскольку партнерский блок вновь сформированного блока порядка 1 также свободен, эти два объединяются в один блок порядка 2.
- Поскольку партнерский блок вновь сформированного блока порядка 2 также свободен, эти два объединяются в один блок порядка 3.
- Поскольку партнерский блок вновь сформированного блока порядка 3 также свободен, эти два объединяются в один блок порядка 4.
Как видите, при запросе памяти происходит следующее:
- Если необходимо выделить память
- Ищите слот памяти подходящего размера (минимум 2k блок, который больше или равен запрошенной памяти)
- Если он найден, он передается программе
- Если нет, то пытается сделать подходящий слот памяти. Система делает это, пробуя следующее:
- Разделите свободный слот памяти, превышающий запрошенный размер, пополам
- Если достигнут нижний предел, выделите этот объем памяти
- Вернитесь к шагу 1 (найдите слот памяти подходящего размера)
- Повторяйте этот процесс, пока не найдете подходящий слот памяти.
- Если память должна быть освобождена
- Освободите блок памяти
- Посмотрите на соседний квартал - он тоже бесплатный?
- Если это так, объедините два и вернитесь к шагу 2 и повторяйте этот процесс, пока не будет достигнут верхний предел (вся память будет освобождена), или пока не встретится несвободный соседний блок.
Реализация и эффективность
По сравнению с другими более простыми методами, такими как динамическое размещение, в системе приятельской памяти мало внешняя фрагментация, и позволяет уплотнение памяти с небольшими накладными расходами. Партнерский метод освобождения памяти быстрый, максимальное количество требуемых уплотнений равно log2(высший порядок). Обычно система распределения напаренной памяти реализуется с использованием двоичное дерево для представления используемых или неиспользуемых разделенных блоков памяти. «Приятеля» каждого блока можно найти с помощью Эксклюзивный или адреса и размера блока.
Однако все еще существует проблема внутренняя фрагментация - память потрачена впустую, потому что запрошенная память немного больше небольшого блока, но намного меньше большого блока. Из-за того, как работает метод распределения памяти напарника, программе, запрашивающей 66 КБ памяти, будет выделено 128 КБ, что приведет к потере 62 КБ памяти. Эту проблему можно решить с помощью размещение плиты, который может быть наложен поверх более грубого вспомогательного распределителя для обеспечения более детального распределения.
Одна из версий алгоритма распределения друзей была подробно описана Дональдом Кнутом в томе 1 книги. Искусство программирования.[2] В Ядро Linux также использует систему друзей с дальнейшими модификациями для минимизации внешней фрагментации, а также различные другие распределители для управления памятью внутри блоков.[3]
джемаллок
[4] это современный распределитель памяти, в котором, помимо прочего, используется метод приятеля.
Смотрите также
Рекомендации
- ^ Кеннет С. Ноултон. Распределитель быстрой памяти. Коммуникации ACM 8 (10): 623–625, октябрь 1965 г. также Кеннет С. Ноултон. Описание L6 программистом. Коммуникации ACM, 9 (8): 616–625, август 1966 г. [см. Также: Google books [1] стр. 85]
- ^ Кнут, Дональд (1997). Фундаментальные алгоритмы. Искусство программирования. 1 (Второе изд.). Ридинг, Массачусетс: Эддисон-Уэсли. С. 435–455. ISBN 0-201-89683-4.
- ^ Мауэрер, Вольфганг (октябрь 2008 г.). Профессиональная архитектура ядра Linux. Wrox Press. ISBN 978-0-470-34343-2.
- ^ Эванс, Джейсон (16 апреля 2006 г.), Масштабируемый одновременный доступ
маллок (3)
Реализация для FreeBSD (PDF), стр. 4–5