Если теперь осуществить вызов Release (P), то указатель заполнения кучи HeapPtr переустановится в «позицию», которая была запомнена ранее в указателе P. Куча примет вид, показанный на рис. 11.5.
Рис. 11.5
- 204 -
Действие Release (P) проявилось в том, что куча вернулась в предыдущее состояние, «забыв» обо всех динамических переменных, созданных после выполнения процедуры Mark(P). Теперь уже не надо освобождать ссылки P3 и P4. Их нет, как будто они и не размещались.
Из механизма работы процедуры Release следует, что всю кучу можно освободить одним оператором Release ( HeapOrg ), который приводит ее к исходному пустому состоянию.
Очевидно, что пара процедур Mark/ Release — это очень мощное средство управления кучей. Они позволяют эффективно освобождать память с минимальными усилиями. Однако за это приходится платить гибкостью использования пространства кучи. При их применении освобождение памяти должно производится в порядке, обратном размещению динамических переменных. Так, например, нельзя удалить переменную P2^, не удалив при этом переменные P3^ и P4^. Для более гибкого использования кучи необходимо применять процедуры Dispose и FreeMem.
Вместе с тем не рекомендуется перемежать вызовы процедур Release с вызовами процедур Dispose и FreeMem. Две последние действуют избирательно и могут освобождать блоки памяти в используемой части кучи. Так, если после строки New(P4) в рассмотренном примере поставить вызов Dispose (P1), то перед выполнением Release (P) на месте динамической переменной P1^ будет пусто, и это пустое место могло бы быть потом использовано для размещения других данных. Координаты этого пустого (свободного) блока хранятся в специальном списке свободных блоков. Процедура Release (P) среди всего прочего стирает список свободных блоков, навсегда блокируя тем самым доступ к свободным блокам, находящимся ниже значения указателя P. Об этом надо помнить всегда, иначе можно легко и незаметно заблокировать всю кучу и потерять массу времени на нетривиальное решение вечного вопроса «почему программа не пошла?»
11.5.4. Функции MaxAvail и MemAvail
Обе эти функции анализируют количество свободной памяти, как еще не использованной, так и получившейся в результате освобождения динамических переменных процедурами Dispose и FreeMem. Возвращаемые значения этих функций имеют тип LongInt.
Функция MaxAvail возвращает длину в байтах самого длинного свободного блока. Она находится как максимальное значение из размера свободной части кучи и размеров освобожденных к данному
- 205 -