| > HeapAvail := LongFreePtr – LongHeapPtr
| END;
| procedure WriteAvail; { вспомогательная процедура }
| >begin
| >WriteLn( ' MemAvail=', MemAvail :6,
| >' MaxAvail=', MaxAvail :6,
| >' HeapAvail=', HeapAvail :6 )
| >end; {WriteAvail}
| VAR { ПРИМЕР АНАЛИЗА ПАМЯТИ КУЧИ }
| > P1, P2 : Pointer;
| BEGIN
| > WriteLn( 'Начало работы:' ); WriteAvail;
| > GetMem ( P1, 1000 ); { отводится 1000 байт в куче }
| > GetMem ( Р2, 10 ); { отводится 10 байт в куче }
| > WriteLn('Размещены в куче 2 переменные(1000 и 10 б)');
| > WriteAvail;
| > FreeMem( P1, 1000 ); { освобождается первый блок }
- 208 -
{Сейчас в куче появилась дыра, а в списке свободных блоков появились ее координаты, уменьшив кучу на 8 байт.}
| > WrfteLn( 'Освобождена ссылка на 1000 байт:' );
| > WriteAvail;
| > FreeMem( P2, 10 ); { освобожден второй блок }
| >{ Теперь вся куча пуста, и нет нужды в списке блоков. }
| > WriteLn( 'Освобождена ссылка на 10 байт:' );
| > WriteAvail;
| > ReadLn { пауза до нажатия клавиши ввода }
| END.
Рис. 11.7 (окончание)
Заметьте, что все локальные параметры в функции HeapAvail имеют тип LongInt, чтобы хранить десятичные значения ненормализованных (абсолютных) адресов. Чтобы избежать потери порядка из-за превышения диапазона типа Word, значения функций Seg(...) перед умножением переписываются в переменную более «длинного» типа LongInt.
Следующий вопрос, связанный со списком свободных блоков, — это потенциальная проблема дробности. Она связана с тем, что дробность в мониторе кучи равна одному байту. Это означает, что при размещении одного байта переменная будет занимать один байт. При размещении и удалении в произвольном порядке большого числа переменных или блоков различной длины могут появляться свободные блоки небольшого размера, причем число таких блоков может быть большим. Так, например, при освобождении блока размером 20 байт и размещении вслед за этим блока размером 19 байт, появится свободный блок длиной 1 байт, который может находиться в списке свободных блоков довольно долго. Для решения этой проблемы справочное руководство по Турбо Паскалю советует воспользоваться следующим приемом. Каждый раз выделять и впоследствии освобождать блок с размером, кратным какому-либо целому числу байтов. Для этого необходимо переопределить процедуры GetMem и FreeMem. Например, если мы хотим выделять память блоками с размером, кратным 16 байт, то переопределения GetMem и FreeMem будут выглядеть следующим образом:
PROCEDURE GetMem( VAR P : Pointer; Size : Word );
BEGIN
System.GetMem(P, (Size+15) and $FFF0);
END; { GetMem }