Программирование в среде Турбо Паскаль (Поляков, Круглов) - страница 132

TYPE

FreeRec = RECORD { Указатели на }

OrgPtr, EndPtr : Pointer; { начало и конец }

END; { блока в куче }

FreeList = Array [0..8190] of FreeRec;

FreeListP = ^FreeList; { ссылка на массив записей }

Поля OrgPtr и EndPtr каждой записи определяют начало и конец каждого свободного блока (EndPtr, точнее говоря, указывает на первый байт после блока) и являются нормализованными указателями.

Фактическое значение самой FreePtr не является постоянным, а как бы перемещается в диапазоне от верхней границы кучи до максимальной длины списка свободных блоков.

Число освобожденных пустых блоков (элементов в массиве FreeList) на текущий момент можно вычислить по формуле

FreeCount := (8192 - Ofs(FreePtr^) div 8) mod 8192;

Максимальное число свободных блоков, которые могут существовать одновременно, равно емкости массива FreeList (8191 блок). Число это достаточно велико, чтобы достичь его на практике. Если же это удастся, то возникнет фатальная ошибка и останов программы.


Ошибка может возникнуть также, когда куча заполнена и список свободных блоков почти смыкается с верхней границей заполнения кучи. При этом попытка освобождения блока, не лежащего на вершине кучи, будет приводить к расширению списка и возникновению ошибочной ситуации. Для решения этой проблемы монитор кучи использует системную переменную FreeMin типа Word, которую можно применять для управления минимальным размером

- 207 -

участка памяти между HeapPtr и списком свободных блоков (FreePtr). Для этого необходимо в FreeMin записать гарантированный размер этого участка в байтах. Чтобы при этом не происходило потерь памяти, значение размера должно быть вычислено как

ЧИСЛО_ЭЛЕМЕНТОВ_СПИСКА_В_ЗАЗОРЕ*8,

где 8 — размер записи FreeRec. Когда значение FreeMin не равно нулю, вызовы процедур New и GetMem будут неэффективными, если они пытаются сделать расстояние между HeapPtr и FreePtr меньше FreeMin. Кроме того, MaxAvail и MemAvail будут вычитать FreeMin из возвращаемых значений.

Иногда необходимо знать величину еще ни разу не использованного пространства кучи (между значениями указателей FreePtr сверху и HeapPtr снизу). Функция HeapAvail, анализирующая размер именно этого пространства (без учета освобожденных блоков в куче), приводится на рис. 11.7.


| >{ $М 1024, 4000, 4000} (*заданные параметры кучи для теста*)

| >FUNCTION HeapAvail : LongInt;

| VAR

| > LongSeg, LongFreePtr, LongHeapPtr : LongInt;

| BEGIN

| > LongSeg := Seg(FreePtr^)+$1000*Byte(Ofs(FreePtr^)=0);

| > LongFreePtr :=(LongSeg * 16 ) + Ofs(FreePtr^);

| > LongSeg := Seg( HeapPtr^);

| > LongHeapPtr := ( LongSeg*16 ) + Ofs( HeapPtr^);