Руководство по языку B.Pascal 7

       

Список свободных блоков


Адреса и размеры свободных блоков, созданных при операциях Dispose и FrееМем, хранятся в списке свободных блоков, который увеличивается вниз, начиная со старших адресов памяти, в сегменте динамически распределяемой области. Каждый раз перед выделением памяти для динамической переменной, перед тем, как динамически распределяемая область будет расширена, проверяется список сво- бодных блоков. Если имеется блок соответствующего размера (то есть размер которого больше или равен требуемому размеру), то он используется.

Процедура Rеlеаsе всегда очищает список свободных блоков. Таким образом, программа динамического распределения памяти "за- бывает" о незанятых блоках, которые могут существовать ниже ука- зателя динамически распределяемой области. Если вы чередуете об- ращения к процедурам Маrk и Rеlеаsе с обращениями к процедурам Dispose и FrееМем, то нужно обеспечить отсутствие таких свободных блоков.

Переменная FreeList модуля System указывает на первый сво- бодный блок динамически распределяемой области памяти. Данный блок содержит указатель на следующий свободный блок и т.д. Пос- ледний свободный блок содержит указатель на вершину динамически распределяемой области (то есть адрес, заданный HeapPtr). Если свободных блоков в списке свободных блоков нет, то FreeList будет равно HeapPtr.

Формат первых 8 байт свободного блока задается типом TFreeRec: type PFreeRec = ^TFreeRec; TFreeRec = record Next: PFreeRec; Size: Pointer; end;

Поле Next указывает на следующий свободный блок, или на ту же ячейку, что и HeapPtr, если блок является последним свободным блоком. В поле Size записан размер свободного блока. Значение в поле Size представляет собой не обычное 32-битовое значение, а "нормализованное" значение-указатель с числом свободных парагра- фов (16-байтовых блоков) в старшем слове и счетчиком свободных байт (от 0 до 15) в младшем слове. Следующая функция BlockSize преобразует значение поля Size в обычное значение типа Longint:

function BlockSize(Size: Pointer): Longint; type PtrRec = record Lo, Hi: Word end; begin BlockSize := Longint(PtrRec(Size)).Hi)*16+PtrRec(Size).Lo end;


Чтобы обеспечить, что в начале свободного блока всегда имеет- ся место для TFreePtr, подсистема управления динамически распре- деляемой областью памяти округляет размер каждого блока, выделен- ного подпрограммами New и GetMem до 8-байтовой границы. Таким образом, 8 байт выделяется для блоков размером 1..8, 16 байт - для блоков размером 9..16 и т.д. Сначала это кажется непроизводи- тельной тратой памяти. Это в самом деле так, если бы каждый блок был размером 1 байт. Но обычно блоки имеют больший размер, поэто- му относительный размер неиспользуемого пространства меньше.

8-байтовый коэффициент раздробленности обеспечивает, что при большом числе случайного выделения и освобождения блоков от- носительно небольшого размера (что типично для записей переменной длины в программах обработки текста) не приведет к сильной фраг- ментации динамически распределяемой области. В качестве примера предположим, что занимается и освобождается блок размером 50 байт. После его освобождения запись о нем включается в список свободных блоков. Этот блок округляется до 56 (7*8) байт. Если в дальнейшем потребуется блок размером от 49 до 56 байт, то данный блок будет полностью повторно использован, а не останется от 1 до 7 байт памяти (использование который маловероятно), которые будут только фрагментировать динамически распределяемую область.


Содержание раздела