Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
программирование 2 семестр 1 курс.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
523.82 Кб
Скачать

Предопределенные указатели Администратор дп(кучи) .

Использование следующих предопределенных указателей.

1)heapOrg-адрес начала кучи

2)heapEnd-адрес конца кучи

3)heapPtr-адрес начала свободного фрагмента.

Значения heapOrg и heapEnd после выделения некоторого размера ДП не изменяется.

Значение указателя heapPtr изменяется после каждого резервирования или освобождения блока приводящего к изменению положения нижней границы свободной области кучи.

После загрузки программы heapOrg и heapPtr – имеют один и тот же адрес, в последствии после работы с динамической памятью картина может быть следующей

Особенности при выделение блоков

Var

P:^Byte;

Под любую динамическую переменную при запросе блока памяти администратор кучи выделяет блок размер которого кратен 8 байтам. Это связанно с тем, что с каждым свободным блоком связывается описатель, представляющей собой запись из двух полей указателей (1 указ.=4 байт) 1 указатель содержит адрес описателя следующего свободного блока, 2 указатель содержит длину следующего свободного блока.

Поскольку длина данной записи 8 байт то размер выделяемого блока в куче не может быть меньше 8 байт поэтому если запрашивается блок размером от 1 до 8 байт то администратор выделит 8 байт, а если от 9 до 16 байт то выделит 16 байт в динамической памяти.

Пример: просмотр количества динамической памяти до и после выделения блока.

Type

T_s=string[1];

Var

P0:^T_s;

Begin

Writeln(memavail); 570200

New(p0);

Writeln(memavail); 570192

Dispose(p0); 570200

Freelist – данный указатель содержит адрес описателя первого свободного блока.

В момент загрузки программы указатели Freelist, heapOrg и heapPtr содержат один и тот же адрес . указатели Freelist и heapPtr в ходе работы с кучей будут иметь одни и те же значения до тех пор пока в куче не образуется свободный блок памяти расположенный ниже границы которую указывает heapPtr на этот блок и будет указывать Freelist.

Если в процессе работы с кучей образуется блок ниже по адресу блока на который указывает Freelist, то этот указатель будет указывать на вновь образовавшийся блок. Если освободившейся блок выше блока с этим указателем то указатель останется на месте.

Если текущий блок является последним в списке свободных блоков то его описатель содержит адрес heapEnd и длину равную 0.

Любой новый блок памяти выделяется с адреса Freelist только в том случае если свободный блок связанный с этим указателем имеет подходящий размер, иначе ищется блок определенного размера путем прохода по всему списку свободных блоков, если подходящий блок не найден, то запрашиваемый блок выделяется адреса heapPtr(если хватает памяти).

Анализ ресурсов дп при размещение динамических данных.

В случае нехватки памяти при размещение динамических данных генерируется код ошибки переполнения которая является фатально прерывающей выполнение программы. В этом случае функция монитора кучи(администратора кучи) возвращает значение 0 Данная функция является системной функцией. Функция монитора кучи эта функция может возвращать несколько значений причем эти значения возвращаются в случае если по запросу операторов new или getmem не может быть выделен блок памяти.

Значения возвращаемые функцией:

0-фатальная ошибка которая приводит к остановки программы (возвращается по умолчанию)

1-вместо аварийного завершения программы при нехватке памяти функция возвращает в указатель или ссылку связанными с процедурами new или getmem значение Nil.

2-в этом случае ошибка заканчивается и происходит повторный запрос .

4.Функция монитора кучи обычно называется HeapFunc(); однако в нашем случае это название является не принципиальным, важным является заголовок этой функции.

Function имя(<размер выделяемого блока>:word):integer(возвращаемое значение);

Размер выделяемого блока определяет значение которое устанавливается при вызове процедуры new или getmem. Адрес функции монитора кучи находится в системной переменной HEAPerror.

Чтобы процедуры размещение динамических данных в памяти не заканчивалось фатально, необходимо перепрограммировать функции монитора кучи так чтобы вместо 0 она возвращала 1 для этого создается пользовательская функция имеющая заголовок аналогично системной функции, которая должна возвращать 1. Адрес этой функции необходимо записать в переменную HEAPerror. Пользовательская функция должна компилироваться в режиме дальнего вызова т.е. в этом случае с функцией связывается адрес , адрес сегмента и адрес смещения.

Построим пользовательскую функцию.

{$f+} устанавливается модель дальнего вызова

Function User_func(size:word):integer;

Begin

User_func:=1;

End;

{$f-}

Еще один способ дальнего вызова

Function User_func():integer;far

Для того чтобы в программе вместо стандартной функции монитора кучи работала пользовательская необходимо адрес пользовательской функции записать в системную переменную HEAPerror.

Begin

HEAPerror:=@user_func;

Пример: требуется выделить два блока памяти для хранения информации размеров в 1 байт и поместить в их некоторые значения. Если под какой либо один или оба блока не хватает памяти то очистить память и завершить выполнение программы.

Программа:

Var

X,y:^byte;

P:pointer;

{$f+}

Function User_f(size:word):integer;

Begin

User_func:=1;

End;

{$f-}

Begin

Mark(p);

Heaperror:=@user_f;

.

.

New(x); new(y);

If y=nil then

Begin

Write(‘’);

Readkey;

Release(p);

Exit;

End;

X^:=3;

Y^:=1;

Release(p);

End.

Лекция № 10

Ссылочный и указательный типы данных. Линейные динамические списки. Определение узла списка. Организация динамических списков типа FIFO, LIFO. Основные операции над списками: добавление узла, вставка узла, удаление узла, просмотр узлов списка. Удаление списка.