Розумне управління пам’яттю з постійними операціями часу?


18

Розглянемо сегмент пам'яті (розмір якого може збільшуватися або зменшуватися, як файл, коли це потрібно), на якому ви можете виконати дві основні операції з розподілу пам'яті, що включають блоки фіксованого розміру:

  • виділення одного блоку
  • звільнення раніше виділеного блоку, який більше не використовується.

Також, як вимога, системі управління пам’яттю не дозволяється переміщатися навколо виділених зараз блоків: їх індекс / адреса повинна залишатися незмінною.

Найбільш наївний алгоритм управління пам'яттю збільшує глобальний лічильник (з початковим значенням 0) і використовує його нове значення в якості адреси для наступного розподілу. Однак це ніколи не дозволить скоротити сегмент, коли залишиться лише кілька виділених блоків.

Кращий підхід: зберігайте лічильник, але підтримуйте список розміщених блоків (що можна робити в постійний час) і використовуйте його як джерело для нових виділень, доки він не буде порожнім.

Що далі? Чи можна зробити щось розумне, все-таки з обмеженнями постійного розподілу часу та розстановки, що дозволило б зберегти сегмент пам'яті якомога коротше?

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


Чи не перевірка списку вже не буде постійним часом, оскільки список може зростати або скорочуватися через деякі виділення / дислокації, зроблені раніше?
Сім

@Sim, я припускав, що це пов'язаний список, і з ним операції будуть , тому що ви завжди працюєте лише з головою. O(N)
svick

Я думаю, що ваш «кращий підхід» вже використовуватиме оптимальну кількість пам’яті, тобто він ніколи не виділяє додаткову пам’ять, якщо є вільний блок. Як ви гадаєте, що «розумний» підхід покращиться на цьому? Ви маєте на увазі, що він повинен виділяти близько до початку, щоб мати більше шансів, що ви зможете скоротити сегмент після угоди?
svick

@Sim: Вибачте, можливо, я мав би використати термін стек (але я вважав, що це може бути заплутаним), "deallocate" - це натиснення, а "виділити" - це поп, або, у випадку, якщо він не вдається, просто повернутися назад до лічильника. Обидва - постійний час.
Стефан Гіменез

Чи є у вас обмеження в режимі реального часу, або ви добре з амортизованим постійним часом? Відповіді, ймовірно, будуть зовсім іншими.
Жил "ТАК - перестань бути злим"

Відповіді:


11

Що стосується блоків фіксованого розміру, то, що ви описали, - це безкоштовний список . Це дуже поширена методика із наступним поворотом: список вільних блоків зберігається у самих вільних блоках. У коді C це виглядатиме так:

static void *alloc_ptr = START_OF_BIG_SEGMENT;
static void *free_list_head = NULL;

static void *
allocate(void)
{
    void *x;

    if (free_list_head == NULL) {
        x = alloc_ptr;
        alloc_ptr = (char *)alloc_ptr + SIZE_OF_BLOCK;
    } else {
        x = free_list_head;
        free_list_head = *(void **)free_list_head;
    }
    return x;
}

static void
release(void *x)
{
    *(void **)x = free_list_head;
    free_list_head = x;
}

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

Зменшуєтьсявказівник на розподіл після випуску може бути складнішим, оскільки вільні блоки можна надійно ідентифікувати лише шляхом слідування вільного списку, який проходить через них у непередбачуваному порядку. Якщо зменшення розміру великого сегмента, коли це можливо, для вас важливо, ви можете скористатися альтернативною технікою з більшими накладними витратами: між будь-якими двома виділеними блоками ви помістите «дірку». Дірки пов'язані разом із подвійно пов'язаним списком у порядку пам'яті. Вам потрібен формат даних для отвору, щоб ви могли знайти адресу початкової дірки, знаючи, де вона закінчується, а також розмір отвору, якщо ви знаєте, звідки починається отвір у пам'яті. Потім, звільняючи блок, ви створюєте дірку, яку ви з’єднуєте з наступною та попередньою дірками, відтворюючи (все ще в постійному часі) упорядкований список усіх дірок. Потім накладні дані - це приблизно два слова розміром указівника на виділений блок; але, за ціною, ви можете надійно виявити виникнення "остаточного отвору", тобто приводу зменшити розмір великого сегмента.

Можливих варіацій багато. Хорошим вступним документом є розподіл динамічного зберігання: опитування та критичний огляд Wilson et al.


4
Як ви знаходите дірки, найближчі до місця угоди, за постійний час?
Рафаель

1
У другому описуваному нами способі дірка - це заголовок (пара покажчиків для списку отворів) разом із простором для нуля, одного або декількох блоків даних. Між будь-якими двома виділеними блоками завжди є отвір, навіть якщо це мікро-діра, що складається лише із заголовка отвору. Тож знайти найближчі отвори легко: вони знаходяться прямо перед і безпосередньо після виїмки. Звичайно, мікро-лунки не є частиною вільного списку (переліку отворів, придатних до розподілу). Ще один спосіб переконатися в тому, що ви додаєте заголовок до кожного блоку та кожного (немікро) отвору (розподілення під 16-бітною Ms-Dos працювало так).
Томас Порнін

4

Ця відповідь стосується загальних методів управління пам’яттю. Я пропустив, що питання задає питання про випадок, коли всі блоки мають однаковий розмір (і вирівнюються).


Основні стратегії, які ви повинні знати, - це першокласна, наступна, найкраща і система приятелів . Я написав короткий підсумок один раз за курс, який я викладав, сподіваюся, він читабельний. Я вказую на досить вичерпне опитування .

На практиці ви побачите різні модифікації цих основних стратегій. Але жодне з них насправді не є постійним часом! Я не думаю, що це можливо в гіршому випадку, використовуючи обмежений об'єм пам'яті.


Цікаво, я мушу це детально прочитати. Однак, схоже, що ці системи стосуються конкретно нестаціонарних розподілів розмірів, з чим я не стикаюся.
Стефан Гіменез

Правильно. Вибачте, я занадто швидко прочитав ваше запитання.
rgrig

О(lgн)

s / найменший вільний блок / вільний блок за найменшою адресою /
rgrig

2

Ви можете ознайомитись з амортизованим аналізом і, зокрема, динамічними масивами. Навіть якщо операції насправді не виконуються в постійному часі на кожному кроці, в перспективі це виглядає так.


2
І як саме динамічні масиви допоможуть розподілити пам'ять?
svick

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