Файл: Функции операционных систем персональных компьютеров (История операционных систем).pdf

ВУЗ: Не указан

Категория: Курсовая работа

Дисциплина: Не указана

Добавлен: 05.04.2023

Просмотров: 91

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

2.1. Загрузка программ

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

На первый взгляд все используемые системы программирования можно разделить на два больших класса: системы со статическим связыванием и системы с динамическим связыванием. Связывание в данном случае означает определение адреса именованного объекта. Зачастую метод связывания явно или неявно определяется спецификацией языка программирования.

В системах с динамическим связыванием программа определяет адрес функции в момент вызова функции. При динамическом связывании в определенных обстоятельствах может оказаться, что в разные моменты по одному и тому же имени могут быть вызваны разные функции. Это может использоваться в различных целях. Таким образом, перегруженные методы в объектно-ориентированном программировании требуют динамического связывания.

Примеры языков с динамическим связыванием это Java и C#. Они осуществляют во время выполнения не только сборку, но и компиляцию программы в машинный код, это называется JIT-компиляцией. Современные реализации виртуальных машин Java и C# могут использовать гибридную стратегию: сразу после запуски они интерпретируют программу и собирают статистику о том какие функции или участки кода вызываются наиболее часто. Если программа работает достаточно долго, то интерпретатор генерирует машинный код и передает управление ему.

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

Примеры языков со статическим связывание: ассемблеры, Fortran, C, C++. Статическое связывание позволяет прописывать адреса объектов непосредственно в адресные поля команд, работающих с этими объектами, поэтому в большинстве случаев оно приводит к повышению скорости исполнения программы.

Как отмечалось выше, объектно-ориентированные языки в определенных ситуациях требуют динамического связывания. В C++ и некоторых других языках эта сложность была решена за счет усложнения языка: методы, для которых требуется динамическая привязка, описываются иначе, чем методы, для которых достаточно привязки статической.


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

Так же есть примеры загрузчиков с отложенным или ленивым связыванием. Ленивый компоновщик определяет адрес функции во время исполнения при первом обращении к ней. Так, функции, к которым не было обращений никогда и не привязываются, как при динамическом связывании. Но, в отличии от динамического компоновщика, ленивый запоминает результаты разрешения имен, и все последующие обращения к функции будут происходить по её адресу.

Самым простым способом загрузки программы является абсолютная загрузка — это загрузка программы с одного и того же адреса. Это возможно если система может предоставить каждому процессу свое адресное пространство или система может исполнять в каждый момент времени только один процесс.

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

Другим способом является относительная загрузка. Относительный способ загрузки заключается в том, что программа загружается каждый раз с нового адреса. При этом в момент компиляции и компоновки неизвестен адрес с которого будет происходить загрузка. Единственное что известно в момент сборки, — это размещение объектов относительно друг друга. Если при загрузке весь модуль будет загружен в непрерывную область памяти, то относительное размещение будет сохранено. Благодаря этому, при сборке программы известна разность адресов объектов, но неизвестны их окончательные адреса. При загрузке такой программы необходимо настроить её новые адреса.


Еще один способ загрузки программ — это оверлейная загрузка. Концепция оверлея состоит в том, чтобы не загружать программу в память целиком, а разбить ее на несколько моделей и помещать их в память по мере необходимости. При этом на одни и те же адреса в разные моменты времени будут загружены разные модули. Необходимость в этом методе загрузки возникает если адресное пространство невелико, а программа достаточно большая.

2.2. Управление оперативной памятью

Основной ресурс, распределением которого занимается ОС, — оперативная память. Поэтому организация памяти оказывает большое влияние на структуру и возможности операционной системы.

Самый простой вариант задачи управления памятью — отсутствие диспетчера памяти, т.е. совпадение физического и логического адресных пространств. В этих условиях ОС не может контролировать доступ пользовательских программ к памяти. Управление памятью со стороны ОС ограничивается только решением вопроса, какая память занята кодом и данными программы, а какая — свободна. Даже в этих условиях управление памятью представляет собой непростую задачу.

В системах с виртуальной памятью возникает вариант той же самой задачи при управлении виртуальным адресным пространством в пределах процесса. Наличие диспетчера памяти дает довольно большую свободу во время отображения адресного пространства на физическую память, но при распределении самого адресного пространства возникает та же самая задача, что и при управлении открытой памятью: необходимо гарантировать, что ни один вновь создаваемый объект не будет конфликтовать по адресам с уже существующими объектами. Многие алгоритмы, первоначально придуманные для управления открытой памятью, находят применение при управлении виртуальным адресным пространством.

В простейших однозадачных ОС, в которых нет никакого диспетчера памяти и допускается работа только одной задачи, программы загружаются с фиксированного адреса. По адресам от 0 до начала программы находятся векторы прерываний. Операционная система находится в старших адресах памяти. Адрес, с которого она начинается, зависит от количества памяти у машины и от конфигурации ОС. В этом случае управление памятью со стороны операционной системы состоит в том, что загрузчик проверяет, поместится ли загружаемый модуль в пространство между адресом с которого загружается программа и адресом памяти с которого начинается ОС. Если объем памяти, которое использует программа, не будет изменяться во время исполнения, то на этом управление заканчивается.


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

Подобным образом происходит выделение адресного пространства в многозадачных ОС с виртуальной памятью. Задача обычно занимает начальные адреса, сначала идет код и статические данные задачи, затем её динамическая память. В простейшем случае все остальное адресное пространство доступно задаче, ОС при этом находится в отдельном адресном пространстве, и задача ее не видит. Благодаря этому, с одной стороны, задача не может повредить код и данные ОС, и, с другой стороны, задача может использовать больше памяти.

В более сложных случаях код и данные занимают несколько несмежных областей в ОЗУ. В таких системах динамическая память обычно оказывается разбита на несколько несмежных областей.

При динамическом выделении памяти запросы на выделение памяти формируются во время исполнения задачи. Динамическое выделение, таким образом, противопоставляется статическому, когда запросы формируются на этапе компиляции программы. В конечном итоге, нередко и те, и другие запросы обрабатываются одним и тем же алгоритмом выделения памяти в ядре ОС, но во многих случаях статическое выделение может быть реализовано более простыми средствами чем динамическое.

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

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

2.3. Запоминающие устройства

Запоминающие устройства служат для хранения информации и обмена ею с другими устройствами. Важнейшими параметрами запоминающих устройств являются информационная ёмкость, организация запоминающего устройства и быстродействие. Эти параметры запоминающих устройств находятся между собой в противоречии, поэтому системам памяти свойственна сложная иерархическая структура, и в зависимости от предназначения запоминающего устройства его реализация может значительно отличатся.


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

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

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

Другой способ управления памятью заключается в том, что память не делиться заранее на разделы, изначально вся память свободна. Каждой вновь поступающей задаче выделяется необходимая ей память, если достаточный объем памяти отсутствует, то задача не принимается и стоит в очереди на выполнение. После завершения задачи память освобождается, и на это место может быть загружена другая задача. Таким образом, в любой момент времени оперативная память представляет из себя случайную последовательность занятый и свободных участков памяти различного размера.

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

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