Слайд 1Алгоритмические языки программирования.
Лектор:
доцент КФТТ И.В.Климов
Слайд 3КАК СОЗДАТЬ ПРОГРАММУ БОЛЬШОГО РАЗМЕРА?
Максимальный размер модуля не может превышать
64 Кбайт.
Однако количество модулей не ограничено, что дает возможность разрабатывать
весьма крупные программы.
Если программа запускается из интегрированной среды Турбо Паскаля, то часть памяти занимает сама среда(около 230 Кбайт).
Эту память можно использовать, если компилировать программу с помощью автономного компилятора (ТРС.ЕХЕ).
А если и этого окажется недостаточно?
Нужно использовать механизм оверлеев!
Слайд 4Оверлей - это такой способ использования оперативной памяти, при котором в один
и тот же участок памяти, называемый оверлейным буфером, попеременно, по
мере надобности, загружаются различные оверлейные модули.
Слайд 5ГДЕ ХРАНЯТСЯ ОВЕРЛЕЙНЫЕ МОДУЛИ?
Все оверлейные модули в готовом к работе
виде хранятся на диске.
В оперативной памяти в каждый момент находится
лишь один активный модуль и, возможно, небольшое число других неактивных модулей.
Слайд 6При выполнении программы, построенной по оверлейному принципу, в памяти находятся
только те из оверлейных процедур и функций, которые необходимы в
данный момент.
Слайд 7Схема работы оверлейной программы
Программа
Главная часть
main
(размер LM байт)
Модули
(LA>LB)
A
(размер LA байт)
B
(размер LB
байт)
Слайд 8ОЗУ
LM
LA
LB
ДИСК
Prog.exe
Неоверлейная (обычная) программа
Слайд 9Оверлейная программа.
ОЗУ
LM
LA
ДИСК
Prog.exe
(main)
A.ovr
B.ovr
Оверлейный буфер
Слайд 10Оверлейная программа.
Последовательность выполнения оверлейной программы
Слайд 11Загрузка нужных модулей в оверлейный буфер осуществляется автоматически и программисту
не нужно об этом заботиться.
Слайд 12Объем памяти, занимаемой оверлейной программой,
определяется длиной главной части и
наибольшего из перекрывающихся модулей
в то время как при неоверлейной структуре
в этот объем входит суммарная длина всех модулей.
Чем больше в программе оверлейных модулей и чем меньше длина наибольшего из них,
тем больший выигрыш в памяти дает оверлейная структура.
Главное преимущество оверлейной структуры:
Слайд 13На каждую загрузку оверлейного модуля с диска в оверлейный буфер
требуется дополнительное время
поэтому оверлейная программа будет в общем случае исполняться
с меньшей скоростью.
Главный недостаток оверлейной структуры:
Слайд 14ОБРАТИТЕ ВНИМАНИЕ!
Оверлеи полезны только в программах DOS, работающих в реальном
режиме.
Работа оверлейных программ обеспечивается с помощью процедур, и функций модуля
OVERLAY.
В программах для Windows и программах, работающих в защищенном режиме, необходимость в использовании оверлеев отпадает
для программ Windows памятью управляет сама оболочка Windows, а для программ, работающих в защищенном режиме, — администратор выполнения (RTM.EXE)
эти средства включают в себя полный механизм обслуживания оверлеев
Слайд 15Оверлейная программа.
оверлейный буфер
область памяти, размещенная между сегментом стека и «кучей»,
в которую загружаются оверлейные модули.
администратор оверлеев
подпрограмма обеспечивающая загрузку оверлеев
в память и выгрузку их на диск
Новые термины и понятия:
Слайд 16Размер оверлейного буфера
По умолчанию для оверлейного буфера устанавливается минимально возможный
размер.
Во время выполнения программы размер буфера может быть легко
увеличен путем выделения дополнительной памяти из динамически распределяемой области.
Слайд 17При компиляции программы, имеющей оверлейную структуру,
наряду с выполняемым файлом
(.ЕХЕ), создается оверлейный файл, с именем, совпадающим с именем главной
программы, и расширением (.OVR).
Файл с расширением .ЕХЕ содержит статические (неоверлейные) части программы.
Файл с расширением .OVR содержит все оверлейные модули, которые при выполнении программы будут подгружаться в память и выгружаться из нее на диск.
Турбо Паскаль управляет оверлеями на уровне модулей
Слайд 18Файл с оверлейной частью программы должен размещаться в том же
каталоге, что и файл с главной частью.
Слайд 19Оптимизация методов управления оверлейным буфером
Слайд 20АДМИНИСТРАТОР ОВЕРЛЕЕВ.
Администратор оверлеев Турбо Паскаля (подсистема управления оверлеями) реализован с
помощью стандартного модуля OVERLAY.
Администратор оверлеев использует усовершенствованные методы управления буферами.
что
обеспечивает оптимальное выполнение программы в имеющейся области памяти
Слайд 21Управление оверлейным буфером
Подсистема управления оверлеями сохраняет в оверлейном буфере столько
оверлеев, сколько возможно.
Это позволяет уменьшить количество считываний оверлеев с диска.
После
загрузки оверлея вызов одной из его подпрограмм выполняется так же быстро, как и обращение к программе, имеющей неоверлейную структуру.
Когда возникает необходимость выгрузить один оверлей, чтобы освободить место для другого, администратор оверлеев сначала пытается выгрузить те оверлеи, которые не являются активными.
Т.е. те, которые в данный момент времени не содержат активных подпрограмм.
Слайд 22ОБРАТИТЕ ВНИМАНИЕ!
Одной из очень важных возможностей администратора оверлеев является возможность
загружать оверлейный файл в дополнительную память при наличии достаточного пространства.
Для
этой цели в Турбо Паскале поддерживается средство расширения памяти EMS (Lotus/Intel/Microsoft Expanded Memory Specification)
Если оверлейный файл размещен в памяти EMS, все последующие загрузки оверлеев осуществляются путем быстрой передачи информации из одной области памяти в другую.
Слайд 24Поскольку оверлеи оформляются в виде модулей, то все правила построения
модулей применимы и к оверлеям.
Оверлей представляет собой обычный модуль, за
исключением нескольких особенностей, присущих только оверлеям: в оверлейных модулях нельзя использовать процедуры обработки прерываний.
Слайд 25ОФОРМЛЕНИЕ ОВЕРЛЕЕВ.
В начале всех оверлейных модулей должна быть размещена директива
компилятора {$О+}.
Процедуры и функции, прямо или косвенно вызывающие оверлейные подпрограммы,
должны быть откомпилированы с ключом {$F+}.
В основной программе либо в первых строках, либо перед каждой процедурой, вызывающей оверлей, необходимо указать директиву {$F+}.
Слайд 26Если директива {$F+} указана перед процедурой, то после нее необходимо
указать обратную директиву {$F-}, чтобы остальные процедуры, не вызывающие оверлей,
не использовали дальний тип вызова, т.к. это может несколько замедлить работу программы.
Слайд 27Оформление оверлеев
Директива компилятора
{$О Имя_Модуля}
используется в программе для указания
того, какой из модулей будет оверлейным.
Эта директива должна размещаться
за оператором USES программы, в котором перед именами всех других оверлейных модулей должно указываться имя стандартного модуля Overlay.
Слайд 28PROGRAM Overlay;
{Все программы должны иметь дальний тип вызова}
{$F+}
{Порядок подключения
оверлейных модулей должен быть таким}
USES Crt, Overlay, Init_Ovr, Ovr_1,0vr_2;
{Указание
компилятору, какие модули являются оверлейными}
{$О Ovr_1}
{$0 Ovr_2}
Оформление оверлеев
Пример:
Слайд 29ОБРАТИТЕ ВНИМАНИЕ!
Если попытаться использовать в качестве оверлейного модуль, при компиляции
которого не была указана директива {$О+}, компилятор выдаст сообщение об
ошибке.
Из всех стандартных модулей оверлейным может быть только модуль Dos.
Другие стандартные модули не могут использоваться в качестве оверлейных.
Не могут быть оверлейными модули, которые содержат обработку прерываний
Программы, содержащие оверлейные модули, должны компилироваться на диск
Если попытаться выполнить компиляцию таких программ в память, то компилятор выдаст сообщение об ошибке.
Слайд 30Если в оверлейном модуле есть раздел инициализации, то в нем,
с одной стороны, нельзя инициализировать администратор оверлеев, а с другой
стороны, нельзя производить какие-либо действия до инициализации администратора.
Чтобы разрешить эту кажущуюся парадоксальной ситуацию необходимо ввести в программу дополнительный неоверлейный модуль, в разделе инициализации которого и будет включаться администратор оверлеев, и подключить его в директиве USES перед оверлейными модулями.
Слайд 31Последовательность создания оверлейных программ.
Слайд 321
Выделить главную часть программы и разбить оставшуюся часть на несколько
модулей.
Продумать состав модулей таким образом, чтобы минимизировать количество их перезагрузок
в буфер в процессе исполнения программы.
2
В главной части программы необходимо указать с помощью директив компилятора вида {$0 <имя> } те модули, которые будут оверлейными.
Учтите, что из всех стандартных библиотечных модулей только один модуль DOS может быть оверлейным, остальные модули не могут объявляться оверлейными.
3
Необходимо предусмотреть перед первым по логике работы программы обращением к какому-либо оверлейному модулю вызов процедуры инициализации оверлея OVRINIT.
Здесь же, если это необходимо, следует установить размер оверлейного буфера и указать возможность использования расширенной памяти.
Слайд 334
В начале главной программы и каждого оверлейного модуля необходимо поместить
директивы компилятора {$O+ } и {$F+}.
Или установить опции OPTIONS/COMPILE /FORCE
FAR CALLS и OPTIONS/COMPILE/OVERLAYS ALLOWED в состояние ОN
5
Откомпилировать программу на диск.
6
Программа готова к работе
Слайд 34Процедуры и функции модуля Overlay
Слайд 35
Инициализация администратора оверлеев.
Анализ результатов инициализации.
Использование расширенной памяти.
Инициализация оверлеев
Слайд 36Процедура OvrInit(OvrFileName : STRING); инициализирует администратор оверлеев и открывает указанный
оверлейный файл (.OVR).
Инициализация администратора оверлеев
Процедура OvrInit является обязательной для всех
программ, использующих оверлеи, и должна выполняться перед первым обращением к любой оверлейной подпрограмме.
Обычно одного вызова этой процедуры достаточно, если при этом не производить контроль ошибок инициализации.
Слайд 37Условие:
Пусть файл с главной частью программы называется MAIN.РАS;
В программе
используются два оверлейных модуля;
Разместим их в файлы UNITA.PAS и UNITB.PAS.
Файл
MAIN.РАS
PROGRAM OverlayDemo;
($F+,O+}
Uses Over1ay, UnitA, UnitB;
{$O UnitA}
{$O UnitB}
BEGIN
OvrInit ('MAIN.OVR');
SubA
END.
Слайд 38Файл UNITA.PAS
UNIT UnitA;
{$F+,0+}
INTERFACE
Uses UnitB;
Procedure SubA;
IMPLEMENTATION
PROCEDURE SubA;
const
st = 'Работает модуль'
BEGIN
writeln (st,
'A');
SubB (st)
END;
END.
Слайд 39Файл UNITB.PAS
UNIT UnitB;
{$F+,0+}
INTERFACE
Procedure SubB (s : string);
IMPLEMENTATION
PROCEDURE SubB ;
BEGIN
writeln (s,
'B');
SubB (st)
END;
END.
Слайд 40Инициализация администратора оверлеев
Хотя использование кода инициализации и допускается в оверлейных
модулях,
по ряду причин его следует избегать.
Код инициализации, даже если
он выполняется только один раз, является частью оверлея и будет занимать пространство в оверлейном буфере при каждой загрузке оверлея.
Если большое число оверлейных модулей содержит код инициализации, каждый из них при загрузке программы придется считывать в память.
Слайд 41Рациональный подход:
весь код инициализации собрать в оверлейный модуль инициализации,
модуль
инициализации вызывается только один раз при загрузке программы
больше программа
к нему не обращается.
Слайд 42В модуле Overlay объявлена переменная
OvrResult : INTEGER;
в которой
хранится код завершения процедур и функций модуля.
в том числе и
код завершения процедуры OvrInit.
Анализ результатов инициализации
Слайд 43Возможные значения переменной OvrResult, а также список соответствующих им констант:
Анализ
результатов инициализации
Слайд 44Использование расширенной памяти
Для размещения оверлеев в расширенной памяти (EMS-памяти), предназначена
процедура OvrInitEMS, не имеющая параметров.
Эта процедура проверяет возможность использования в
системе расширенной памяти, и если это возможно, то оверлейный файл полностью размещается там.
Процедура OvrInitEMS не является обязательной и не заменяет процедуру OvrInit. При использовании расширенной памяти необходимо вызывать обе эти процедуры.
Слайд 45Рекомендуется всегда использовать процедуру OvrInitEMS.
в случае неудачного завершения она никак
не повлияет на работу программы и не вызовет появления фатальной
ошибки
в случае удачного завершения вся работа с оверлеями будет происходить в памяти, что приведет к значительному ускорению работы программы.
Слайд 46
Механизм управления буфером.
Управление механизмом испытаний.
Управление оверлейным буфером
Слайд 47УПРАВЛЕНИЕ ОВЕРЛЕЙНЫМ БУФЕРОМ
Обычно размер оверлейного буфера автоматически определяется таким, что
в нем может разместиться самый крупный из всех оверлейных модулей.
Для
большинства программ этого может быть достаточно, однако возможна ситуация, при которой одна из функций программы реализуется с помощью двух или более модулей, каждый из которых является оверлейным.
Если суммарный размер таких модулей больше, чем размер наибольшего оверлея, то частое обращение модулей друг к другу приведет к слишком частому обмену информацией между диском и памятью, что замедлит работу программы.
Программист может увеличить размер буфера.
Тогда при загрузке в буфер очередного модуля программа проверит, достаточно ли в буфере свободного места, и, если места достаточно, загрузит новый модуль сразу за старым, который таким образом не будет уничтожен.
Слайд 48Для управления оверлейным буфером применяется функция OvrGetBuf,
а также процедуры
OvrSetBuf и OvrClearBuf.
Использование этих процедур необходимо в том случае, когда
системные средства модуля по управлению оверлейным буфером по каким-либо причинам не устраивают программиста, и возникает необходимость самостоятельно управлять конфигурацией и содержимым буфера.
Слайд 49Функция OvrGetBuf: Longint;
Данная функция возвращает размер установленного оверлейного буфера в
байтах
В этом ее отличие от специальной переменной OvrHeapSize модуля System,
в которой хранится не текущий, а начальный размер буфера.
Слайд 50Процедура OvrSetBuf(Size : Longint);
Данная процедура устанавливает новый размер буфера и
должна вызываться после процедур OvrInit и OvrInitEMS.
Параметр Size определяет размер
буфера в байтах. Этот размер не должен быть меньше первоначально установленного и не должен превышать размер доступной памяти.
Слайд 51Доступный объем памяти определяется разницей значений переменных MaxAvail, содержащей размер
максимального непрерывного блока кучи, и OvrHeapSize, содержащей начальный размер буфера.
Если
значение параметра Size превышает текущий размер буфера, то недостающий объем памяти выделяется из кучи, а если меньше, то излишек помечается как свободный и возвращается в кучу.
Слайд 52УПРАВЛЕНИЕ ОВЕРЛЕЙНЫМ БУФЕРОМ
После вызова процедуры OvrSetBuf необходимо проверить значение переменной
OvrResult.
Если ее значение равно OvrError, то это может быть обусловлено
следующими причинами:
в куче с помощью процедур New и GetMem уже были размещены динамические переменные;
значение Size слишком мало для создания буфера;
не была проведена процедура инициализации.
Слайд 53Процедура OvrClearBuf;
Данная процедура выполняет принудительную очистку оверлейного буфера (т.е. выгружает
все расположенные в нем оверлейные модули).
Используется в тех случаях, когда
необходимо освободить динамическую память для размещения в ней каких-либо переменных.
Для определения адресов начала и конца буфера можно использовать специальные переменные OvrHeapOrg и OvrHeapEnd модуля System.
Слайд 54Модуль_1
Модуль_2
……..
……….
Модуль_N
Оверлейный буфер Турбо Паскаля лучше всего представить в виде кольцевого
буфера.
указатель начала
указатель конца
Оверлеи всегда загружаются в начало буфера. При
этом более "старые" оверлеи смещаются к его концу.
Когда буфер заполняется, то выгружается оверлей в конце буфера, если он в данный момент не используется, и выделяется место для новых оверлеев.
Этот режим используется администратором оверлеев по умолчанию.
Однако Турбо Паскаль предоставляет возможность оптимизировать алгоритм управления оверлеями.
Механизм управления буфером
Слайд 55ПРОБЛЕМА В УПРАВЛЕНИИ ОВЕРЛЕЯМИ.
Предположим, что оверлей А содержит некоторые часто
используемые подпрограммы.
Хотя некоторые из этих подпрограмм используются все время, существует
вероятность, что оверлей А будет выгружен из буфера и вскоре загружен в него снова.
Проблема заключается в том, что подсистема управления оверлеями ничего не знает о частоте вызовов подпрограмм в оверлее А.
Она знает только, что если при обращении к подпрограмме оверлея А его нет в памяти, то нужно загрузить этот оверлей.
Одно из возможных решений — перехватывать каждое обращение к оверлею А и при каждом вызове перемещать его в начало буфера, чтобы было отражено его новое состояние — как последнего использованного оверлея.
Такой перехват вызовов будет слишком непроизводительным и в некоторых случаях может даже более замедлить работу программы, чем дополнительная операция загрузки оверлея.
Слайд 56В Турбо Паскале найдено компромиссное решение этой проблемы, которое не
приводит к непроизводительным расходам ресурсов и обеспечивает высокую степень успеха
в идентификации последних использованных оверлеев, которые не следуют выгружать.
Слайд 57Оптимизация алгоритма управления оверлеями
Когда оверлей приближается к концу буфера, начинается
его испытание.
Если в ходе испытания выполняется вызов подпрограммы данного оверлея,
то он не будет выгружен, когда достигнет конца оверлейного буфера.
Вместо этого он просто перемещается в начало буфера, и начинается новый цикл его перемещения по кольцевому оверлейному буферу.
Если же в процессе испытания обращений к оверлею не будет, то оверлей при достижении конца буфера выгружается.
Слайд 58Использование механизма испытаний (проб/отказов) приводит к тому, что часто используемые
оверлеи будут сохраняться в оверлейном буфере за счет того, что
будет перехватываться почти каждый вызов, когда оверлей приближается к концу оверлейного буфера.
Слайд 59УПРАВЛЕНИЕ МЕХАНИЗМОМ ИСПЫТАНИЙ.
Для управления механизмом испытаний предназначены
функция OvrGetRetry и
процедура OvrSetRetry.
Функция OvrGetRetry: Longlnt;
возвращает текущий установленный размер области испытаний.
В
начале работы программы размер области испытаний всегда равен нулю.
Процедура OvrSetRetry(Size: Longlnt);
устанавливает размер Size области испытаний.
Параметр Size определяет размер этой области в конце буфера.
Данная процедура должна вызываться после процедур OvrInit и OvrInitEMS.
Слайд 60По умолчанию механизм испытаний не используется.
Если по каким-то причинам он
необходим, то обычно рекомендуется назначать размер области испытаний, равный примерно
одной трети буфера.
Обычно это выполняется командой
OvrSetRetry(OvrGetBuf DIV 3);