Происхождение блоков связано со случайной последовательностью использования процедур NEW—DISPOSE или GETMEM— FREEMEM ("ячеистая" структура кучи). Поле NEXT в записи TFREEREC содержит адрес описателя следующего по списку свободного блока кучи или ад- адрес, совпадающий с HEAPEND, если этот участок последний в списке. Поле SIZE содержит ненормализованную длину свободного блока или 0, если ниже адреса, содержащегося в HEAPPTR, нет свободных блоков., Ненормализованная длина оп- определяется так: в старшем слове этого поля содержится количество свободных параграфов, а в младшем — количество свободных байтов в диапазоне 0—15.
Следующая функция преобразует значение поля SIZE в фактическую длину свобод- свободного блока: Function BlockSizelSize: pointer): Longint; {Функция преобразует ненормализованную длину свободного блока в байты} type PtrRec = record Lo, Hi : word end; var LengthBlock: Longmt; begin BlockSize := Longlnt(PtrRec(Size).Hi)*16 + PtrRec(S.ze).Lo end; Сразу после загрузки программы указатели heabptr и E'REELIST содержат один и тот же адрес, который совпадает с началом кучи (этот адрес содер- содержится в указателе HEAPORG) При этом в первых 8 байтах кучи хранится за- запись, соответствующая типу TFREEREC (поле NEXT содержит адрес, совпа- совпадающий со значением HEAPEND, а поле SIZE — ноль, что служит дополнительным признаком отсутствия "ячеек" в динамической памяти). При работе с кучей указатели HEAPPTR и FREELIST будут иметь одинаковые значения до тех пор, пока в куче не образуется хотя бы один свободный блок ниже границы, содержащейся в указателе HEAPPTR.
Как только это произойдет, указатель FREELIST станет ссылаться на начало этого блока, а в первых 8 байтах освобожденного участка памяти будет размещена запись TFREEREC Используя FREELIST как начало списка, программа пользователя всегда сможет просмотреть весь список свободных блоков и при необходимости модифицировать его. Описанный механизм вскрывает один не очень существенный недостаток, связанный с работой администратора кучи, а именно: в любой освободившийся блок администратор должен поместить описатель этого блока, а это означает, что длина блока не может быть меньше 8 байт. Администратор кучи всегда выцеляет память блоками, размер которых кратен размеру записи TFREEREC, т. е. кратен 8 байтам. Даже если программа запросит 1 байт, администратор выделит ей фактически 8 байт. Те же 8 байт будут выделены при запросе 2, 3, ..., 8 байт; при запросе 9 байт будет выделен блок в 16 байт и т. д.
Это обстоятельство следует учитывать, если вы хотите минимизировать возможные потери динамической памяти. Если запрашиваемый размер не кратен 8 байтам, в куче образуется "дырка" размером от 1 до 7 байт, при- 17Q Часть I. Ядро Турбо Паскаля чем она не может использоваться ни при каком другом запросе динамической памяти вплоть до того момента, когда связанная с ней переменная не будет удалена из кучи. Если при очередном обращении к функции NEW или GETMEM администратор не может найти в куче нужный свободный блок, он обращается к функции, адрес которой содержит переменная HEAPERROR
Эта функция соответствует следующему процедурному типу: type HeapErrorFun = function (Size : word) : Integer; Здесь SIZE — размер той переменной, для которой нет свободной динамической памяти. Стандартная функция, адрес которой при запуске программы содержит переменная heaperror, возвращает 0, что приводит к останову программы по ошибке периода счета с кодом 203 (см. приложение 3). Вы можете переопределить эту функцию и таким образом блокировать останов программы. Для этого необходимо написать собственную функцию и поместить ее адрес в указатель HEAPERROR. Например: Function HeapFunc(SlZe: Word) : Integer; far; begin HeapFunc := 1 end; begin {Основная программа) HeapError := @HeapFunc; end.
Отметим, что функция типа HEAPERRORFUN вызывается только в том случае, когда обращение с требованием выделения динамической памяти было не- неуспешным. Она может возвращать одно из трех значений: ? 0 — прекратить работу программы; 0 1 — присвоить соответствующему указателю значение NIL и продолжить работу программы; 0 2 — повторить выделение памяти; разумеется, в этом случае внутри функции типа HEAPERRORFUN необходимо освободить память нужного размера.
1. Бройдо В.Л. Теория информации. Учебное пособие.- 2-е изд.- СПб: Питер, 2005.- 702с.
2. Под ред. А.Д.Урсула. История Прикладная теория информации Учебное пособие. СПб: РАГС, 2006.- 433 с.
3. Под ред. А.Д.Хомоненко Основы современных компьютерных технологий: Учебник/ - СПб: Корона принт, 2009.- 672 с.
4. М.: ФАИР-ПРЕСС Организация информационного производства: Учебное пособие.-, 2005.- 247 с..-(Специальный издательский проект для библиотек)
5. Петров Ю.П. Оперативная память. / Ю.П.Петров.- СПб: БХВ-Петербург, 2005.- 441 с.-(Учебное пособие)