Читайте также:
|
|
Исключить фрагментацию кучи позволяет применение процедур Mark (метить) и Release (освобождать).
Процедура Mark (Var P: Pointer) запоминает в указателе Р нижнюю текущую границу свободной памяти кучи — адрес первой свободной ячейки, расположенной сразу же за конечной ячейкой объекта самой последней динамической переменной. Таким образом, в Р запоминается адрес первой ячейки неиспользуемой части кучи. В этом случае динамическая переменная-указатель фактически дублирует функции типизированной константы-указателя HeapPtr и с успехом может быть заменена ею.
Процедура Release (Var P:Pointer) возвращает кучу в состояние, которое было зафиксировано ранее в Р вызовом процедуры Mark. Если после вызова процедуры Mark(P) вы порождали (при помощи New или GetMem) целый ряд новых динамических переменных (любых типов), то вызов процедуры Release (P) после таких порождений передвигает нижнюю границу свободного пространства кучи HeapPtr с позиции (с адреса), которую она занимала после порождения последней динамической переменной, в позицию (в адрес), которая ранее была зафиксирована в указателе Р. При этом все переменные, порожденные после вызова процедуры Mark(P), уничтожаются и все смежные блоки ячеек уничтоженных переменных пригодны для размещения в них любых других динамических переменных без эффекта фрагментации.
Если перед порождением первой динамической переменной в типизированную константу-указатель HeapOrg записать исходное состояние кучи (при помощи Mark(HeapOrg)), то вызовом процедуры Release (HeapOrg) можно полностью освободить кучу от всех динамических переменных, которые до такого вызова порождались, например, вызовом процедуры New.
Приведем поясняющий фрагмент программы:
Var
Р:Pointer;
Pl,P2,P3,P4:^Real;
BEGIN
New(Pl);
New(P2);
Mark(P);
New(P3);
New(P4);
Mark(HeapPtr);
Release(P)
Mark(HeaPtr);
После вызова двух последних процедур приведенного фрагмента программы в указателях Р и PheaPtr будет записан один и тот же адрес — указатель первой ячейки кучи, расположенной за последней ячейкой объекта самой «верхней» динамической переменной Р2. Переменные РЗ и Р4, порожденные после Р2, будут уничтожены и адрес, записанный в Р, окажется адресом первой ячейки неиспользованной памяти кучи: новой нижней границы свободной области кучи.
При таком способе управления кучей нельзя удалить, например, переменную Р2, не удалив при этом переменные РЗ и Р4. Это ограничение является определенным недостатком процедур Mark и Release. Для более гибкого использования кучи необходимо применять процедуру Dispose или FreeMem.
В одной и той же программе не рекомендуется применение «блочных» процедур Mark и Release совместно с процедурами Dispose и FreeMem. Это обусловлено следующим обстоятельством. При использовании процедур Dispose и FreeMem параллельно с освобождением ими блоков памяти объектов конкретных динамических переменных адреса (координаты) освобожденных блоков заносятся в специальный список адресов и объемов свободных блоков, который применяется всякий раз для последующего размещения в куче новых динамических переменных. Процедура же Release(P) не только перемещает указатель на новую нижнюю границу свободной части кучи, но и стирает весь список свободных блоков. Таким образом, если освобожденный процедурой Dispose или FreeMem блок памяти оказался ниже указателя Р, то после применения процедуры Release (P) до конца работы программы в этом блоке больше не размещаются новые динамические переменные с использованием процедур New или GetMem. Это необходимо всегда помнить, дабы постепенно не заблокировать всю кучу от размещения там каких-либо переменных.
В заключение отметим, что хорошим стилем программирования является уничтожение динамических переменных после их обработки (если это даже не требуется для размещения новых динамических переменных) или в конце программы. Это означает, что для каждой процедуры New должна иметься парная ей процедура Dispose, а для каждой процедуры GetMem — процедура FrееМеm. Если применяется блочная работа с динамической памятью при помощи подпрограмм Маrk Re lease, то перед порождением первой динамической переменной необходимо вызвать процедуру Mark(P), а в конце программы — процедуру Release(P) для полного освобождения кучи от динамических переменных вашей программы. Нарушение этих рекомендаций не приведет к сбоям в работе программы, а будет лишь свидетельствовать о плохом стиле программирования автора программы.
Дата добавления: 2015-07-11; просмотров: 91 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Процедуры New и Dispose | | | Цель и задачи изучения дисциплины, ее место в учебном процессе |