Учебное пособие по курсу Программирование на языке высокого уровня для вузов по специальности 230105 Программное обеспечение вычислительной техники и автоматизированных систем
Скачать 0.64 Mb.
|
. Возвращает размер в байтах наибольшего непрерывного участка кучи. Обращение: MAXAVAIL Результат имеет тип LONGINT. За один вызов процедуры NEW или GETMEM нельзя зарезервировать памяти больше, чем значение, возвращаемое этой функцией. PDF created with pdfFactory Pro trial version www.pdffactory.com 69 Функция MEMAVAIL. Возвращает размер в байтах общего свободного пространства кучи. Обращение: MEMAVAIL Результат имеет тип LONGINT. Процедура NEW. Резервирует фрагмент кучи для размещения переменной. Обращение: NEW(TP) Здесь TP - типизированный указатель. За одно обращение к процедуре можно зарезервировать не более 65521 байта динамической памяти. Если нет свободной памяти требуемого размера, возникает ошибка периода исполнения. Если память не фрагментирована, последовательные обращения к процедуре будут резервировать последовательные участки памяти, так что начало следующего будет располагаться сразу за концом предыдущего. Процедура NEW может вызываться как функция. В этом случае параметром обращения к ней является тип переменной, размещаемой в куче, а функция NEW возврвщает значение типа указатель. Например: type Plnt =^integer; var p: Plnt; p := New(Plnt); При размещении в динамической памяти об'екта разрешается в качестве второго параметра обращения к NEW указывать имя конструктора. Функция OFS. Возвращает значение типа WORD, содержащее смещение адреса указанного об'екта. Вызов: OFS(X) Здесь Х - выражение любого типа или имя процедуры. Функция PTR. Возвращает значение типа POINTER по заданному сегменту SEG и смещению OFS. Вызов: PTR(SEG,OFS) Здесь SEG - выражение типа WORD, содержащее сегмент; OFS - выражение типа WORD, содержащее смещение; PDF created with pdfFactory Pro trial version www.pdffactory.com 70 Значение, возвращаемое функцией, совместимо с указателем любого типа. Процедура RELEASE. Освобождает участок кучи. Обращение: RELEASE(PTR) Здесь PTR - указатель любого типа, в котором предварительно было сохранено процедурой MARK значение указателя кучи. Освобождается участок кучи от адреса, хранящегося в PTR, до конца кучи. Одновременно уничтожается список всех свободных фрагментов, которые, возможно, были созданы процедурами DISPOSE или FREEMEM. Функция SEG. Возвращает значение типа WORD, содержащее сегмент адреса указанного об'екта. Вызов: SEG(X) Здесь Х - выражение любого типа или имя процедуры. Функция SIZEOF. Возвращает длину в байтах внутреннего представления указанного об'екта. Вызов: SIZEOF(X) Здесь Х - имя переменной, функции или типа. Например, везде в программе из примера 13 вместо константы SIZEOFREAL можно было бы использовать обращение SIZEOF(REAL). Администратор кучи . Как уже отмечалось, администратор кучи - это служебная программа, которая обеспечивает взаимодействие пользовательской программы с кучей. Администратор кучи обрабатывает запросы процедур NEW, GETMEM,DISPOSE,FREEMEM и др. и изменяет значения указателей HEAPPTR и FREELIST. Указатель HEAPPTR содержит адрес нижней границы свободной части кучи, а указатель FREELIST - адрес описателя первого свободного блока. В модуле SYSTEM указатель FREELIST описан как POINTER, однако фактически он указывает на следующую структуру данных: type PFreeRec = ^TFreeRec; TFreeRec = record Next : pointer; PDF created with pdfFactory Pro trial version www.pdffactory.com 71 Size : pointer end; Эта списочная структура предназначена для описания всех свободных блоков памяти, которые расположены ниже границы HEAPPTR. Происхождение блоков связано со случайной последовательностью использования процедур NEW-DISPOSE или GETMEM-FREEMEM ("ячеестая" структура кучи). Поле NEXT в записи TFREEREC содержит адрес описателя следующего по списку свободного блока кучи или адрес, совпадающий с HEAPEND, если этот участок последний в списке. Поле SIZE содержит ненормализованную длину свободного блока или 0, если ниже адреса,содержащегося в HEAPPTR, нет свободных блоков. Ненормализованная длинаопределяется так: в старшем слове этого поля содержится количество свободных параграфов, а в младшем - количество свободных байт в диапазоне 0...15. Следующая функция преобразует значение поля SIZE в фактическую длину свободного блока: Function BlockSize(Size: pointer):Longint; { Функция преобразует ненормализованную длину свободного блока в байты } type PtrRec = record Lo, Hi : word end; var LengthBlock : longint; BEGIN BlockSize := Longint(PtrRec(Size).Hi)*16 + PtrRec(Size).Lo END; Сразу после загрузки программы указатели HEAPPTR и FREELIST содержат один и тот же адрес, который совпадает с началом кучи (этот адрес содержится в указателе HEAPORG). При этом в первых 8 байтах кучи хранится запись, соответствующая типу TFREEREC (поле NEXT содержит адрес, совпадающий со значением HEAPEND, а поле SIZE - ноль, что служит дополнительным признаком отсутствия "ячеек" в динамической памяти). При работе с кучей указатели HEAPPTR и FREELIST будут иметь одинаковые значения до тех пор, пока в куче не образуется хотя бы один свободный блок ниже границы, содержащейся в указателе HEAPPTR. Как только это произойдет, указатель FREELIST станет ссы аться на начало этого блока, а в первых 8 байтах освобожденного участка памяти будет размещена запись TFREEREC. Используя PDF created with pdfFactory Pro trial version www.pdffactory.com 72 FREELIST как начало списка, программа пользователя всегда сможет просмотреть весь список свободных блоков и при необходимости модифицировать его. Описанный механизм вскрывает один весьма существенный недостаток, связанный с работой администратора кучи в версии 6.0: в любой освободившийся блок администратор должен поместить описатель этого блока, а это означает, что длина блока не может быть меньше 8 байтов. Администратор кучи всегда выделяет память блоками, размер которых кратен размеру записи TFREEREC, т.е. кратен 8 байтам. Даже если программа запросит 1 байт, администратор выделит ей фактически 8 байт. Те же 8 байт будут выделены при запросе 2, 3,..., 8 байт; при запросе 9 байт будет выделен блок в 16 байт и т.д. Это обстоятельство следует учитывать, если Вы хотите минимизировать возможные потери динамической памяти. Если запрашиваемый размер не кратен 8 байтам, в куче образуется "дырка" размером от 1 до 7 байт, причем она не может использоваться ни при каком другом запросе динамической памяти вплоть до того момента, когда связанная с ней переменная не будет удалена из кучи. Если при очередном обращении к функции NEW или GETMEM администратор не может найти в куче нужный свободный блок, он обращается к функции, адрес которой содержит переменная HEAPERROR. Эта функция соответствует следующему процедурному типу: type HeapErrorFun = function (Size : word) : integer; Здесь SIZE - размер той переменной, для которой нет свободной динамической памяти. Стандартная функция, адрес которой при запуске программы содержит переменная HEAPERROR, возвращает 0, что приводит к останову программы по ошибке периода счета с кодом 203. Вы можете переопределить эту функцию и таким образом блокировать останов программы. Для этого необходимо написать собственную функцию и поместить ее адрес в указатель HEAPERROR. Например: FUNCTION HeapFunc(Size : Word) : integer; far; begin HeapFunc := 1 end; HeapError := @HeapFunc; PDF created with pdfFactory Pro trial version www.pdffactory.com 73 Отметим, что функция типа HEAPERRORFUN вызывается только в том случае, когда обращение с требованием выделения динамической памяти было неуспешным. Она может возвращать одно из трех значений: .0 - прекратить работу программы; .1 - присвоить соответствующему указателю значение NIL и продолжить работу программы; .2 - повторить выделение памяти; разумеется, в этом случае внутри функции типа HEAPERRORFUN необходимо освободить память нужного размера. PDF created with pdfFactory Pro trial version www.pdffactory.com |