Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Praktikum_po_programmirovaniyu.doc
Скачиваний:
23
Добавлен:
09.12.2018
Размер:
2.5 Mб
Скачать

8.1. Структура оперативной памяти для программ на Turbo Pascal

Рассмотрим общую схему использования оперативной памяти программами на Turbo Pascal.

На персональном компьютере адреса задаются совокупностью двух шестнадцатеричных слов, которые называются сегментом и смещением. Сегмент – это участок памяти, имеющий длину 64 Кбайт (65536 байт) и начинающийся с физического адреса, кратного 16 (0, 16, 32, 48 и т.д.). Смещение указывает, сколько байт от начала сегмента необходимо пропустить, чтобы обратиться к нужному адресу.

Параграфом называется непрерывный фрагмент памяти, объемом в 16 байт. Сегмент адресует с точностью до

параграфа, смещение с точностью до байта. Поэтому, абсолютный адрес образуется следующим образом: сегмент*16 + смещение.

В начале любой программы, выполняемой в среде DOS, операционная система формирует префикс сегмента программы (PSP). PSP занимает 256 байт памяти и его адрес хранится в переменной PrefixSeg модуля System. PSP содержит характеристики программы, используемые MS DOS при загрузке программы в оперативную память, например, размер программы, параметры вызова.

140

За PSP следует кодовый сегмент головной программы, ее exe-файл.

Далее расположены кодовые сегменты модулей в порядке, обратном их следованию в операторе uses. Последний кодовый сегмент занимает библиотека времени выполнения (модуль System). Размер кодового сегмента не может превышать 64 Кбайт, количество кодовых сегментов ограничено имеющейся оперативной памятью.

Сегмент данных содержит значения всех типизированных констант, собранных компилятором из всех описаний программы, независимо от уровня вложенности. Далее хранятся глобальные переменные, описанные во внешнем блоке. Память под эти объекты выделяется статически на основе подсчета суммарного объема, необходимого для хранения типизированных констант и глобальных переменных. Размер сегмента данных составляет 64 Кбайт. Сегмент данных адресуется посредством регистра DS (Data Segment). Регистр DS никогда не изменяется во время выполнения программы. Содержимое этого регистра может быть получено с помощью стандартной функции Dseg модуля System.

Сегмент стека используется для управления локальными переменными подпрограмм. Сегмент стека

адресуется специальным регистром SS (Stack Segment), значение которого не изменяется во время выполнения программы. Другой регистр процессора SP(Stack Pointer) всегда показывает адрес свободной области сегмента стека. Значение этого регистра меняется в процессе вызова подпрограмм и выхода из них. Значения регистров SS и SP можно просмотреть, используя соответственно стандартные функции Sseg и Sptr. Для просмотра содержимого всех регистров процессора можно воспользоваться командой Register пункта Debug. Для просмотра содержимого стека

141

Верхняя граница памяти DOS

HeapEnd

С

HeapPtr

вободная область кучи

Д

HeapOrg

инамическая область (растет вверх)

О

OvrHeapOrg

верлейный буфер

С

Sseg:Sptr

тек (растет вниз)

Sseg:0000

Свободный стек

С

Dseg:0000

егмент данных

Кодовый сегмент модуля System

Кодовые сегменты модулей

Кодовый сегмент главной программы

П

PrefixSeg

рефикс сегмента программы (PSP)

используется команда Call Stack пункта Debug. В раскрывающемся при этом окне будет показана

последовательность процедур, вызываемых используемой программой, а также имена процедур и значения передаваемых им параметров. Размер сегмента стека не превышает 64 Кбайт, размер по умолчанию 16 Кбайт. Управлять размером стека можно директивой компилятора $M.

Оверлейный буфер используется стандартным модулем Overlay для хранения оверлейного кода. Оверлейный режим работы состоит в размещении всех модулей или их части на жестком диске и последовательной загрузке модулей в

142

оперативную память по мере их надобности. Размер оверлейного буфера по умолчанию соответствует размеру наибольшего оверлея в программе. Если в программе нет оверлеев, размер оверлейного буфера равен нулю. Размер оверлейного буфера может быть увеличен с помощью программы OvrSetbuf модуля Overlay.

За оверлейным буфером располагается динамическая область памяти, называемая кучей. Куча занимает всю или часть свободной памяти, оставшейся после загрузки программы. Размер кучи можно установить с помощью директивы компилятора {$M стек, min кучи, max кучи}.

Для работы с указателями и адресами используются следующие функции:

Addr(x): pointer – возвращает адрес заданного объекта x;

Cseg: word – возвращает текущее значение регистра CS;

Dseg: word – возвращает текущее значение регистра DS;

Ofs(x): word – возвращает смещение заданного объекта;

Ptr(Seg, Ofs: word): pointer – преобразует сегмент Seg и смещение Ofs в значение типа указатель.

Seg(x): word – возвращает сегмент для заданного объекта;

Sptr: word – возвращает текущее значение регистра PS;

Sseg: word – возвращает текущее значение регистра SS.

Параметр стек – определяет размер сегмента стека в байтах. По умолчанию размер стека 16384 байта.

Максимальный размер – 65538 байт; Min кучи – минимальный требуемый размер кучи в байтах; по умолчанию 0 байт; Max кучи – максимальное размер кучи в байтах; по умолчанию 655360 байт, то есть, вся доступная память, это значение не должно быть меньше наименьшего размера кучи. Все значения задаются в десятичной или шестнадцатеричной формах. Следующие директивы эквивалентны: {$M 16384, 0, 65536} {$M $4000, $ 0, $A000} Если указанный минимальный объем не доступен, то программа не будет выполняться.

143

Управление размещением переменных в динамической памяти осуществляет монитор кучи, являющийся одной из управляющих программ модуля System. Для реализации программ распределения динамической памяти монитор кучи использует следующие переменные:

HeapOrg – указатель начала кучи;

HeapPtr – текущий указатель кучи;

FreePtr – указатель списка свободных блоков

HeapError – указатель установки обработки ошибок кучи;

FreeMin – минимальный размер списка свободных блоков.

Верхняя граница памяти DOS

HeapEnd

С

FreePtr

HeapPtr

писок свободных блоков в куче с их адресом и размером (растет вниз)

Д

HeapOrg

инамическая область (растет вверх)

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

1. Куча пуста. Это состояние возможно в начале выполнения программы или после полной очистки. Тогда монитор кучи заполняет кучу последовательно в порядке поступления запросов на выделение памяти. При каждом выделении памяти монитор кучи передвигает указатель кучи вверх на размер запрошенной области.

2. Куча фрагментирована, т.е., в процессе работы образовались освобожденные участки (дырки). Монитор кучи, следуя принципу оптимального использования памяти,

144

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

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

Когда куча заполнена полностью, то очередной запрос к выделению памяти останавливает программу и выдается сообщение об ошибке с номером 203 (HeapOverlov error). В этом случае нужно увеличить память директивой $M и перезапустить программу. Максимальный размер запрашиваемой памяти, которая может быть размещена в куче, составляет 65521 байт, так как этот участок должен целиком содержаться в одном сегменте.

Рассмотрим организацию списка свободных блоков. Когда участок памяти освобождается, то информация об его расположении в куче помещается в список свободных блоков, который растет от верхней границы кучи (навстречу указателю кучи) по мере поступления информации об освобожденных участках. Перед выделением памяти монитор кучи проверяет список свободных блоков на наличие в нем блока, размер которого равен или больше размера запрашиваемого блока. Список свободных блоков может

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

145