Оверлеї (перекриття)
Ще цікавіший спосіб завантаження програми —
це оверлейне завантаження (over-lay, лежачий зверху) або, як це називали
в старій російськомовній літературі, перекриття. Сенс оверлею полягає в
тому, аби не завантажувати програму в пам'ять цілком, а розбити її на
декілька модулів і поміщати їх в пам'ять в міру необхідності. При цьому на
одні і ті ж адреси в різні моменти часу відображуватимуть різні модулі
(мал. 3.7). Звідси і назва.

Мал. 3.7. Образ процесу з декількома оверлеями
Потреба в такому способі завантаження
з'являється, якщо у нас віртуальний адресний простір малий, наприклад 1 Мбайт
або навіть всього 64 Кбайт (на деяких машинах з RT-11 бувало і по 48 Кбайт,
і багато корисних програм нормально працювали!), а програма
відносно велика. На сучасних 32-розрядних системах віртуальний
адресний простір зазвичай вимірюється гігабайтами, і більшості програм цього
вистачає, а проблеми з браком можна вирішувати зовсім іншими способами. Проте,
існують різні системи, навіть і 32-розрядні, в яких немає пристрою
управління пам'яттю, і розмір віртуальної пам'яті не може перевищувати об'єму
мікросхем ОЗУ, встановлених на платі. Приклад такої системи — згадуваний
вище трансп'ютер.
Поважно
підкреслити, що, не дивлячись на певну схожість між завданнями,
що вирішуються механізмом перекриттів і віртуальною адресацією, одне у жодному
випадку не є різновидом іншого. При віртуальній адресації ми
вирішуємо задачу відображення великого адресного простору на обмежену
оперативну пам'ять. При використанні оверлею ми вирішуємо задачу відображення
великої кількості об'єктів в обмежений адресний простір.
Основна проблема при оверлейному завантаженні полягає в наступному: перш
ніж посилатися на оверлейну адресу, ми повинні зрозуміти, який з оверлейних
модулів в даний момент там знаходиться. Для заслань на функції це просто:
замість точки входу функції ми викликаємо деяку процедуру, звану менеджером
перекриттів (overlay manager). Ця процедура знає, який модуль
куди завантажений, і при необхідності "підкачує" те, що завантажено
не було. Перед кожним засланням на оверлейні дані ми повинні виконувати
аналогічну процедуру, що набагато збільшує і уповільнює програму.
Інколи такі дії покладаються на програміста (Win 16, Mac OS до версії
10 — детальніше управління пам'яттю в цих системах описується в разд.
Управління пам'яттю в MACOS і Win 16), інколи
— на компілятор (handle pointer в Zortech C/C++ для MS DOS), але найчастіше
з оверлейними даними взагалі вважають за краще не мати справи. В
такому разі оверлейним є лише код.
У старих підручниках по програмуванню і керівництві по
операційних системах приділялася багато уваги тому, як розподіляти процедури
між оверлейними модулями. Дійсно, завантаження модуля з диска
є досить тривалим процесом, тому хотілося б мінімізувати
її. Для цього потрібно, аби кожен оверлейний модуль був як можна більш
самодостатнім. Якщо це неможливо, прагнуть винести процедури, на
які посилаються з декількох оверлеїв, в окремий модуль, званий
резидентною частиною або резидентним
ядром. Це модуль, який завжди знаходиться в пам'яті і не розділяє
свої адреси ні з яким іншим оверлеєм. Природно, оверлейний менеджер
має бути частиною цього ядра.
Кожен оверлейний модуль може бути як абсолютним, так і переміщуваним.
Від цього декілька міняється пристрій менеджера, але не більш того. На
архітектурі типа i80x86 можна робити оверлейні модулі, кожен з яких
адресується відносно значення базового регістра
cs і посилається на дані, статично
розміщені в пам'яті, відносно постійного значення регістра DS. Такі модулі
можна завантажувати в пам'ять з будь-якої адреси, можливо, навіть упереміж
з даними. Саме так і поводяться оверлейні менеджери компіляторів Borland і
Zortech.
|