|
||||||||||||||||||||||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Размер страниц и фрагментацияЕсли пользовательская программа и данные занимают ровно целое число страниц, то когда они время от времени загружаются в память, свободного места там не остается. В то же время, если они не занимают ровно целое число страниц, на последней странице останется неиспользованное пространство. Например, если программа и данные занимают 26 000 байт на машине со страницами по 4096 байт, то первые 6 страниц будут заполнены целиком, что в сумме даст 6 х 4096 = 24 576 байт, а последняя страница будет содержать 26 000 - 24576 = 1424 байта. Поскольку в каждой странице имеется пространство для 4096 байт, 2672 байта останутся свободными. Всякий раз, когда страница 7 будет оказываться в памяти, эти байты останутся неиспользуемыми, бесполезно занимая место в основной памяти. Эта проблема получила название внутренней фрагментации (поскольку неиспользуемое пространство является внутренним по отношению к странице). Если размер страницы составляет n байт, то среднее неиспользуемое пространство последней страницы программы будет равно n /2 байт. Таким образом, чтобы свести к минимуму объем бесполезного пространства, страницы должны быть небольшими. Однако при маленьких страницах потребуется много страниц и большая таблица страниц. Если таблица страниц сохраняется аппаратно, то для хранения большой таблицы страниц нужно много регистров, что повышает стоимость компьютера. Кроме того, при запуске и остановке программы на загрузку и сохранение этих регистров потребуется больше времени. Больше того, маленькие страницы снижают эффективность использования пропускной способности диска. Поскольку перед началом передачи данных с диска приходится ждать примерно 10 миллисекунд (время поиска плюс задержка вращения), выгодно передать побольше данных. При скорости передачи данных 10 Мбайт/с, передача 8 Кбайт по сравнению с передачей 1 Кбайт добавляет всего 0,7 миллисекунд. Однако у маленьких страниц есть свои преимущества. Если рабочее множество состоит из большого количества маленьких отделенных друг от друга областей виртуального адресного пространства, то при небольшом размере страницы реже будет возникать пробуксовка (режим интенсивной подкачки), чем при большом. Рассмотрим матрицу A размером 10 000 х 10 000, которая хранится в последовательных 8-байтных словах (A [1,1], A [2,1], A [3,1] и т. д.). При такой записи элементы строки 1 (A [1,1], A [1,2], A [1,3] и т. д.) будут начинаться на расстоянии 80 000 байт друг от друга. Программе, обрабатывающей элементы этой строки, потребуется 10 000 областей, каждая из которых отделена от следующей величиной 79 992 байт. Если бы размер страницы составлял 8 Кбайт, для хранения всех страниц понадобилось бы 80 Мбайт. A При размере страницы в 1 Кбайт для хранения всех страниц потребуется всего 10 Мбайт ОЗУ. При размере памяти в 32 Мбайт и размере страницы в 8 Кбайт программа войдет в режим интенсивной подкачки, а при размере страницы в 1 Кбайт этого не произойдет.
Сегментация Другой подход к организации памяти опирается на тот факт, что программы обычно разделяются на отдельные области-сегменты. Каждый сегмент представляет собой отдельную логическую единицу информации, содержащую совокупность данных или программ и расположенную в адресном пространстве пользователя. Сегменты создаются пользователями, которые могут обращаться к ним по символическому имени. В каждом сегменте устанавливается своя собственная нумерация слов, начиная с нуля. Обычно в подобных системах обмен информацией между пользователями строится на базе сегментов. Поэтому сегменты являются отдельными логическими единицами информации, которые необходимо защищать, и именно на этом уровне вводятся различные режимы доступа к сегментам. Можно выделить два основных типа сегментов: программные сегменты и сегменты данных (сегменты стека являются частным случаем сегментов данных). Поскольку общие программы должны обладать свойством повторной входимости, то из программных сегментов допускается только выборка команд и чтение констант. Запись в программные сегменты может рассматриваться как незаконная и запрещаться системой. Выборка команд из сегментов данных также может считаться незаконной и любой сегмент данных может быть защищен от обращений по записи или по чтению. Для реализации сегментации было предложено несколько схем, которые отличаются деталями реализации, но основаны на одних и тех же принципах. В системах с сегментацией памяти каждое слово в адресном пространстве пользователя определяется виртуальным адресом, состоящим из двух частей: старшие разряды адреса рассматриваются как номер сегмента, а младшие - как номер слова внутри сегмента. Наряду с сегментацией может также использоваться страничная организация памяти. В этом случае виртуальный адрес слова состоит из трех частей: старшие разряды адреса определяют номер сегмента, средние - номер страницы внутри сегмента, а младшие - номер слова внутри страницы. Как и в случае страничной организации, необходимо обеспечить преобразование виртуального адреса в реальный физический адрес основной памяти. С этой целью для каждого пользователя операционная система должна сформировать таблицу сегментов. Каждый элемент таблицы сегментов содержит описатель (дескриптор) сегмента (поля базы, границы и индикаторов режима доступа). При отсутствии страничной организации поле базы определяет адрес начала сегмента в основной памяти, а граница - длину сегмента. При наличии страничной организации поле базы определяет адрес начала таблицы страниц данного сегмента, а граница - число страниц в сегменте. Поле индикаторов режима доступа представляет собой некоторую комбинацию признаков блокировки чтения, записи и выполнения. Таблицы сегментов различных пользователей операционная система хранит в основной памяти. Для определения расположения таблицы сегментов выполняющейся программы используется специальный регистр защиты, который загружается операционной системой перед началом ее выполнения. Этот регистр содержит дескриптор таблицы сегментов (базу и границу), причем база содержит адрес начала таблицы сегментов выполняющейся программы, а граница - длину этой таблицы сегментов. Разряды номера сегмента виртуального адреса используются в качестве индекса для поиска в таблице сегментов. Таким образом, наличие базово-граничных пар в дескрипторе таблицы сегментов и элементах таблицы сегментов предотвращает возможность обращения программы пользователя к таблицам сегментов и страниц, с которыми она не связана. Наличие в элементах таблицы сегментов индикаторов режима доступа позволяет осуществить необходимый режим доступа к сегменту со стороны данной программы. Для повышения эффективности схемы используется ассоциативная кэш-память. Отметим, что в описанной схеме сегментации таблица сегментов с индикаторами доступа предоставляет всем программам, являющимся частями некоторой задачи, одинаковые возможности доступа, т. е. она определяет единственную область (домен) защиты. Однако для создания защищенных подсистем в рамках одной задачи для того, чтобы изменять возможности доступа, когда точка выполнения переходит через различные программы, управляющие ее решением, необходимо связать с каждой задачей множество доменов защиты. По многим причинам гораздо удобнее использовать два или несколько отдельных виртуальных адресных пространств. Например, компилятор может иметь несколько структур, которые создаются в процессе компиляции; такими структурами могут быть:
Каждая из первых четырех структур постоянно растет в процессе компиляции. Размер последней структуры меняется совершенно непредсказуемо. В одномерной памяти эти пять структур пришлось бы разместить в виртуальном адресном пространстве в виде смежных областей, как показано на рис. 6.6. Посмотрим, что произойдет, если программа содержит очень большое число переменных. Область адресного пространства, предназначенная для таблицы символов, может переполниться, даже если в других таблицах полно свободного места. Компилятор, конечно, может сообщить, что он не способен продолжать работу из-за большого количества переменных, но можно без этого и обойтись, поскольку в других таблицах много свободного места. Рис. 7.6. Если в одномерном адресном пространстве размер структур постоянно растет, одна из них может "врезаться" в другую Компилятор может забирать свободное пространство у одних структур и передавать другим, но это будет напоминать управление оверлеями вручную -некоторое неудобство в лучшем случае и долгая нудная работа в худшем. На самом деле нужно просто освободить программиста от необходимости думать о расширении и сокращении структур, подобно тому, как виртуальная память позволяет забыть о разбиении программы на оверлеи. Для этого нужно создать множество абсолютно независимых адресных пространств, которые называются сегментами. Каждый сегмент состоит из линейной последовательности адресов от 0 до какого-либо допустимого максимума. Разные сегменты могут иметь разную длину (обычно так и бывает). Более того, длина сегмента может меняться во время выполнения программы. Длина стекового сегмента может увеличиваться всякий раз, когда что-либо помещается в стек, и уменьшаться, когда что-либо выталкивается из стека.
Рис. 7.7. Сегментированная память позволяет менять размер каждой структуры независимо от других Так как каждый сегмент образует отдельное адресное пространство, разные сегменты могут увеличиваться или уменьшаться независимо друг от друга и не влияя друг на друга. Если стеку в определенном сегменте потребуется больше адресного пространства (чтобы стек мог расти), он может получить его, поскольку его адресному пространству больше не во что "врезаться". Естественно, сегмент может переполниться, но это происходит редко, поскольку сегменты очень большие. Чтобы задать адрес в двухмерной памяти, программа должна указать номер сегмента и адрес внутри сегмента. Сегментированная память изображена на рис. 7.7. Подчеркнем, что сегмент является логическим элементом, о котором программист знает и который он использует. Сегмент может содержать процедуру, массив, стек или ряд скалярных переменных, но обычно в него входит только один тип данных. Сегментированная память имеет и другие преимущества, помимо упрощения работы со структурами данных, которые постоянно меняются в размерах. Если каждая процедура занимает отдельный сегмент, в котором первый адрес - это адрес 0, то сборка процедур, скомпилированных раздельно, значительно упрощается. Когда все процедуры программы скомпилированы и собраны, при вызове процедуры из сегмента п для обращения к слову 0 будет использоваться адрес (n, 0). Если процедура в сегменте п впоследствии будет изменена и перекомпилирована, то другие процедуры менять не потребуется (поскольку их начальные адреса не изменятся), даже если новая версия окажется больше по размеру, чем предыдущая. В одномерной памяти процедуры обычно располагаются друг за другом, и между ними нет свободного адресного пространства. Следовательно, изменение размера одной процедуры может повлиять на начальные адреса других процедур. Это, в свою очередь, потребует изменения всех других процедур, которые вызывают любую из указанных. Если в программу включено множество процедур, переделка оказывается весьма трудоемкой. Сегментация облегчает совместное использование процедур или данных несколькими программами. Если компьютер содержит несколько программ, работающих параллельно (это может быть реальный или моделируемый параллелизм), и все эти программы вызывают одни и те же процедуры, снабжать каждую программу отдельными копиями процедур расточительно для памяти. Если же сделать каждую процедуру отдельным сегментом, их легко можно будет использовать совместно, что исключит необходимость создавать физические копии каждой разделяемой процедуры. В результате мы сэкономим память. Поскольку каждый сегмент являет собой логический объект (например, процедуру, массив или стек), о существовании которого знает программист, разные сегменты можно защищать по-разному. Например, сегменту с процедурой можно назначить атрибут "только для выполнения", запретив тем самым считывание из него и запись в него. Для массива с плавающей точкой можно разрешить только чтение и запись, но не выполнение и т. д. Такая защита часто помогает выявлять программные ошибки. Нужно понимать, почему защита имеет смысл только для сегментированной памяти и не имеет никакого смысла для одномерной (линейной) памяти. Обычно в сегменте не могут находиться одновременно процедура и стек (только что-нибудь одно). Поскольку каждый сегмент содержит объект только одного типа, он может использовать защиту, подходящую для этого типа. Страничная организация памяти и сегментация сравниваются в табл. 1. Таблица 1. Сравнение страничной организации памяти и сегментации
Содержимое страницы в каком-то смысле случайно. Программист может ничего не знать о страничной организации памяти. В принципе можно поместить несколько битов в каждый элемент таблицы страниц для доступа к нему, но чтобы использовать эту особенность, программисту придется следить за границами страницы в адресном пространстве. Но ведь механизм разбиения памяти на страницы был придуман именно для устранения подобных трудностей. Что же касается сегментации, то поскольку у пользователя создается иллюзия, что все сегменты постоянно находятся в основной памяти, к ним можно обращаться и не следить при этом за оверлеями. Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.004 сек.) |