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

- 209 -

PROCEDURE FreeMem( VAR P : Pointer; Size : Word );

BEGIN

System.FreeMem( P, (Size+15) and $FFF0);

END; { FreeMem }

В этом случае минимальный размер свободного блока будет не меньше 16 байт. Однако это будет справедливо до тех пор, пока не будут применены процедуры New и Dispose. Процедура New, например, может для переменной, имеющей размер, не кратный 16 байт, использовать такой свободный блок, что останется пустой излишек с размером менее 16 байт. И уж он-то будет находиться в памяти очень долго. Ситуация осложняется еще тем, что мы теперь уже не можем так просто управлять размером выделяемого блока. Возможным средством улучшить ситуацию является приведение размера динамической переменой к величине, кратной 16 байт. Так, например, если необходимо размещать в куче переменные типа:

TYPE

Dot = RECORD x,y : Real END;

размером 12 байт (6+6), то его размер необходимо увеличить еще на 4 байта. Для этого вместо приведенного выше описания необходимо дать следующее:

TYPE

Dot = RECORD

х, у : Real;

foo : Array [1..4] of Byte

END;

Теперь при размещении переменной типа Dot память будет выделяться и, что самое главное, освобождаться блоками по 16 байт. Заметим, что в принципе можно было бы отказаться от использования процедур New и Dispose и управлять памятью с помощью одних лишь процедур GetMem и FreeMem, хотя это вызвало бы определенные трудности при работе с объектами.

11.5.6. Обработка ошибок распределения памяти


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

FUNCTION ИмяФункции( Size : Word ) : Integer;


- 210 -

Обычно ее называют HeapFunc. Эта функция вызывается в случае, когда New или GetMem не может обработать запрос на распределение кучи. Параметр Size содержит размер блока, который не мог быть распределен, и функция обработки ошибки должна попытаться освободить блок размером не меньше Size. В качестве результата функция должна возвращать значения 0, 1 или 2. В случае 0 немедленно будет возникать фатальная ошибка и останов программы. В случае 1 вместо аварийного завершения процедуры New или GetMem будет возвращаться указатель, равный nil. Наконец, 2 означает как бы замалчивание ошибки, но вызывает повторение запроса на распределение, что, впрочем, может опять вызвать ошибку.

Необходимо, чтобы эта функция компилировалась в режиме {$F+}. Функция обработки ошибки (пусть в программе она названа UserHeapFunc) может быть подставлена в монитор кучи присваиванием ее адреса системной переменной HeapError: