- •1.1. Основные этапы создания программы
- •1.2. Алгоритмы
- •2.1. Структура типов в Turbo Pascal
- •Стандартные скалярные типы. Типы целых чисел
- •2.3. Операции побитовой обработки
- •2.4. Представление вещественных чисел в эвм
- •2.5. Символьный тип
- •2.6. Булевский тип
- •2.7. Перечисленный тип
- •2.8. Интервальный тип (диапазон)
- •3.1. Структура программы на turbo pascal
- •3.2. Основные операторы языка
- •3.2.1. Простые операторы
- •3.2.2. Операторы ввода-вывода
- •3.2.3. Структурные операторы
- •3.2.4. Условные операторы
- •3.2.5. Операторы повтора (цикла)
- •4.1. Массивы
- •4.2. Строковый тип
- •4.3. Множества
- •5.1. Процедуры и функции
- •5.2. Процедуры и функции пользователя
- •5.3. Передача параметров по значению и по ссылке
- •5.4. Рекурсивные процедуры и функции
- •6.1. Структура модулей
- •6.2. Компиляция и использование модулей
- •7.1. Записи
- •7.2. Вложенные записи
- •7.3. Записи с вариантами (вариантные записи)
- •7.4. Файлы
- •7.5. Подпрограммы для работы с файлами
- •7.5.1. Процедуры
- •7.5.2. Функции
- •7.6. Примеры программ для обработки файлов
- •7.7. Текстовые файлы
- •8.1. Структура оперативной памяти для программ на Turbo Pascal
- •8.2. Динамические структуры данных
- •8.3. Основные процедуры и функции для работы с динамическими переменными
- •8.4. Динамика выделения памяти в куче
- •8.5. Линейные списки. Способы создания и обработки
- •8.6. Нелинейные списки. Способы создания и обработки
- •Библиографический список
- •Оглавление
- •394026 Воронеж, Московский просп., 14
8.3. Основные процедуры и функции для работы с динамическими переменными
Процедура New(r) резервирует фрагмент памяти в куче для размещения новой переменной, причем r – указатель на переменную того типа, который нужно создать. Физически r содержит адрес первого байта памяти, где записана переменная. Сам по себе указатель занимает в памяти всего 4 байта, а данные, на которые он указывает, могут занимать в памяти много килобайт. Каждая отдельная процедура new может разместить только одну динамическую переменную.
Процедура Dispose(r) освобождает участок памяти, занятый объектом с указателем r и помещает адрес освобожденного участка и его длину в список свободных блоков.
Процедура Mark(r) позволяет получить адрес динамически распределенной памяти, соответствующий указателю R.
Процедура Release(R) освобождает всю область динамической памяти, начиная с адреса, полученного в результате выполнения процедуры Mark.
П
Процедура FreeMem(r, i) освобождает байт динамически распределенной памяти, выделенных процедурой GetMem.
Функция MaxAvail возвращает размер в байтах максимального непрерывного участка свободной памяти в куче. Результат имеет тип LongInt.
Функция MemAvail возвращает размер в байтах общего свободного участка кучи. Результат имеет тип LongInt.
149
8.4. Динамика выделения памяти в куче
Рассмотрим фрагмент программы:
var p1,p2,p3,p4,p5: ^real;
b
new(p1);
new(p2);
mark(p5);
new(p3);
new(p4);
Этому фрагменту программы соответствует следующая структура динамической памяти:
Младшие адреса памяти
|
|
|
|
Процедура Mark () как бы помечает кучу перед размещением динамической переменной , копируя значения текущего указателя кучи () в указатель .
Если выполнить процедуру Release (), то структура кучи будет такой:
150
|
|
|
|
При этом освобождается вся память, выделенная после обращения к процедуре Mark. Если выполнить Release (HeapOrg), то куча будет очищена полностью, так как указатель HeapOrg содержит адрес начала кучи.
В случае произвольного освобождения динамической памяти удобнее использовать Dispose и FreeMem. При этом, если освобождаемый участок не является последним (верхним) в куче, то куча становится фрагментированной, причем адрес и размер этого свободного участка записывается в список свободных блоков для дальнейшего использования.
Е
|
|
|
|
151
Если сделать New (), то это опять приведет к выделению той же области памяти. С другой стороны Dispose () увеличивает размер свободного участка, так как и были соседними. Этот свободный участок сольется со свободной памятью кучи, так как последний значащий указатель кучи – это . При этом указатель кучи переместится на первый байт после конца последнего занятого участка, и куча будет находиться в том же состоянии, в каком она была бы при выполнении процедуры Release ():
|
|
|
|