Файлы, отображаемые на память 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Файлы, отображаемые на память



Нетрудно понять, что те же средства, которые используются для отображения исполняемого файла на виртуальную память, могут быть применены и к любому другому файлу. В Windows программистам предоставляется возможность создавать и использовать объекты типа «отображение файла» (file mapping).

Работа с таким объектом требует предварительной подготовки. Сначала программа должна создать объект, вызвав функцию CreateFileMapping. Среди параметров этой функции можно отметить:

· хэндл предварительно открытого файла, который будет отображаться на память;

· тип доступа к объекту (только для чтения или и для записи);

· размер объекта;

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

Функция возвращает хэндл созданного или открытого объекта.

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

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

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

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

Если два процесса работают с одним и тем же объектом «отображение файла» и участки файла, которые они отображают в свою память, хотя бы частично пересекаются, то Windows гарантирует, что любые изменения данных, сделанные на этом участке одним процессом, сейчас же становятся доступными другому процессу. Таким образом, два процесса фактически работают с общей областью памяти, как показано на рис. 5‑5.

Рис. 5‑5

С этой точки зрения, отображение файлов можно рассматривать как одно из средств взаимодействия процессов, позволяющее под контролем системы преодолеть изоляцию памяти процессов.

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

Стеки и кучи

Описанные выше средства управления памятью, основанные на выделении регионов, представляют собой мощный и красивый инструмент для работы с большими массивами памяти. Однако в практике программирования чаще встречаются прозаические задачи, связанные с использованием небольших участков памяти: вызов функций с передачей им параметров и выделением локальных переменных, создание и освобождение переменных в динамической памяти и т.п. Но зато эти мелкие операции могут выполняться очень много раз. Использовать выделение отдельного региона ради того, чтобы получить 10 – 20 байт памяти, это примерно то же самое, что применять ракетное оружие в борьбе с тараканами. Напомним, что минимальный размер региона равен 4 Кб.

Программисты привыкли, что для размещения параметров и локальных переменных функций используется стек, а выделение участков динамической памяти происходит из «кучи» – специально предназначенной для этого области памяти, управляемой исполняющей системой языка программирования. Оба этих механизма получают поддержку со стороны Windows.

При создании новой нити она получает свой собственный стек, размер которого, если он не указан явно, принимается равным 1 Мб. Эта величина может показаться явно избыточной для большинства программ. Стоит ли системе так швыряться памятью?

На самом деле, выделяется 1 Мб резервированной памяти. Реального расходования ресурсов памяти при этом не происходит, разве что от 2 Гб адресного пространства процесса отщипывается сравнительно небольшой кусочек. Размер «настоящей» памяти, закрепленной за стеком в страничном файле, равен поначалу двум страницам, размещенным в самом конце зарезервированного региона, как показано на рис. 5‑6.

Рис. 5‑6

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

А почему необходим такой барьер?

Для размещения динамических переменных удобно использовать объект «куча» (heap). Windows предоставляет каждому процессу собственную кучу, хэндл которой можно получить вызовом функции GetProcessHeap. После этого нити процесса могут запрашивать блоки памяти из кучи, вызывая функцию HeapAlloc. Параметры этой функции включают в себя хэндл кучи, размер запрашиваемого блока и некоторые флаги. По истечении надобности в выделенном блоке он может быть возвращен в кучу вызовом функции HeapFree.

Небольшая проблема возникает в связи с тем, что к одной и той же куче могут обращаться разные нити одного процесса. Не исключено их одновременное обращение к функциям, работающим с кучей. Возникает проблема взаимного исключения, и Windows решает ее, используя встроенный мьютекс. Это называется сериализацией доступа к куче, т.е. последовательным выполнением запросов (от «serial» – последовательный). Для программы пользователя этот мьютекс не виден и можно не обращать на него внимания. Однако в том случае, если программист уверен, что нити не могут помешать друг другу, он может отключить сериализацию, указав соответствующий флаг или при открытии кучи, или при запросе блока. Это несколько повышает производительность.

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

· Если с кучей работают две или более нитей процесса, то выделение отдельной кучи для каждой нити позволяет обойтись без сериализации, повысив таким образом производительность.

· Если программа запрашивает из кучи блоки различного размера, то неизбежно такое знакомое нам явление, как фрагментация памяти. В данном случае она приведет к излишнему росту кучи и к замедлению работы. Иногда удается избежать фрагментации, выделив отдельную кучу для каждого используемого размера блоков. Например, из одной кучи будут запрашиваться блоки только размером 105 байт, а из другой – размером 72 байта. При выделении блоков одного размера фрагментации не возникает.

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

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

Управление памятью в UNIX

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

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

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

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

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

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

В современных реализациях, основанных на страничной организации памяти, значительную роль играет понятие списка свободных страниц, которые могут быть немедленно выделены, если какой-либо процесс обратится к виртуальной странице, отсутствующей в памяти. В этот список заносятся страницы, к которым долго не было обращения со стороны процессов. Поскольку в отношении страниц памяти трудно реализовать алгоритм LRU, обычно используется более простой алгоритм «второго шанса» (его другое название – «алгоритм часов»). Идея заключается в следующем. Для каждой физической страницы в таблице страниц хранятся бит использования и бит модификации. Эти биты устанавливаются аппаратно: бит использования – при каждом обращении к странице, а бит модификации – при записи на страницу. Системный процесс, называемый демоном замещения страниц, активизируется периодически (по таймеру) и следит, не слишком ли мал размер списка свободных страниц. Обычно порог устанавливается равным ¼ общего объема физической памяти. Если число свободных страниц ниже этого порога, демон начинает циклически проверять все физические страницы. Если у страницы установлен бит использования, то этот бит сбрасывается. Если же бит уже был сброшен, то страница включается в список свободных. Таким образом, страница попадает в список свободных, если после последнего обращения к ней страничный демон успел дважды ее опросить. Если у страницы установлен бит модификации (в другой терминологии, если страница «грязная»), то перед ее зачислением в список свободных система сохраняет данные в страничном файле. Зачисление в список свободных страниц не означает немедленной потери данных, и если процесс успеет обратиться к странице до того, как она будет отдана другому процессу, эта страница будет исключена из числа свободных.

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

Здесь описан (весьма приблизительно) лишь один из вариантов управления памятью, реализованных в различных версиях UNIX и в Linux. Поскольку алгоритмы управления физической памятью являются «внутренним делом» системы и не регламентируются никакими стандартами, соответствующие алгоритмы, используемые в разных версиях системы, могут значительно отличаться.

Литература

1. Олифер В.Г., Олифер Н.А. Сетевые операционные системы. СПб.: Питер, 2001. 544 с.

2. Таненбаум Э. Современные операционные системы. СПб.: Питер, 2002. 1040 с.

3. Столлингс В. Операционные системы. М.: Вильямс, 2002. 848 с.

4. Бек Л. Введение в системное программирование. М.: Мир, 1988. 448 с.

5. Краковяк С. Основы организации и функционирования ОС ЭВМ. М.: Мир, 1988. 480 с.

6. Кейслер С. Проектирование операционных систем для малых ЭВМ. М.: Мир, 1986. 680 с.

7. Шоу А. Логическое проектирование операционных систем. М.: Мир, 1981. 360 с.

8. Рихтер Дж. Windows для профессионалов. М.: Издательский отдел «Русская редакция» ТОО “Channel Trading Ltd.”, 1995. 720 с.

9. Питрек М. Секреты системного программирования в Windows 95. Киев, Диалектика, 1996. 448 с.

10. Питрек М. Внутренний мир Windows. Киев, «ДиаСофт Лтд.», 1995. 416 с.

11. Робачевский А.М. Операционная система UNIX. СПб.: БХВ, 1999. 528 с.

12. Дансмур М., Дейвис Г. Операционная система UNIX и программирование на языке Си. М.: Радио и связь, 1989. 192 с.

13. Бах М. Архитектура операционной системы UNIX.

14. Финогенов К.Г. Самоучитель по системным функциям MS-DOS. М.: Радио и связь, Энтроп, 1995. 382 с.

15. Кнут Д. Искусство программирования. Т.1, Основные алгоритмы. М.: Вильямс, 2002. 720 с.

16. http://www.citforum.ru

17. http://www.rsdn.ru

18. http://www.emanual.ru

19. http://www.infocity.kiev.ua

20. http://www.helloworld.ru

21. http://www.msdn.microsoft.com

22. http://www.sysinternals.com

23. http://www.bcd.org

24. http://www.linux.org

25. http://www.informit.com

 


[1] Как вспоминает один из разработчиков первого советского компьютера МЭСМ (Малая(!) Электронная Счетная Машина), когда этого монстра включали, то приходилось в январе месяце открывать все окна, чтобы удержать температуру в машинном зале в пределах 30°.

[2] Источник термина не совсем понятен. Среди значений английского слова «cash» наиболее подходящим кажется «наличные деньги» - та мелочь в кошельке, которая позволяет не обращаться каждый раз в банк ради мелких покупок.

[3] Вспомните, как поступает Windows при очередной загрузке после некорректного выключения компьютера.

[4] Теоретически можно задать число копий FAT, отличное от двух. Это число хранится как один из параметров в BOOT-секторе. На практике всегда используются две копии FAT.

[5] Как вы думаете, в чем разница между перемещением файла в пределах одного диска и перемещением с диска на диск?

[6] Придумано около десятка неудачных вариантов русского эквивалента для термина «handle», среди них – дескриптор, ссылка, логический номер, ключ, манипулятор, описатель, индекс... Выразительнее всего был бы прямой перевод – «рукоятка», но ни у кого не хватает смелости, чтобы ввести такой «несерьезный» термин. Так что давайте удовольствуемся честной транслитерацией «хэндл».

[7] Налицо некоторый разнобой в общепринятой терминологии: в системе с невытесняющей диспетчеризацией вытеснение процесса все-таки возможно, но только по инициативе самого процесса.

[8] Иногда используют также термин «разделение времени» (time sharing). Однако этот термин лучше оставить для обозначения многотерминальных ОС, описанных в п. 1.3.3. К системам с квантованием времени относятся также ОС реального времени, заметно отличающиеся от систем разделения времени.

[9] Но к экзамену вспомнить!

[10] Одно и то же расширение EXE означает различные форматы программ для MS-DOS и для Windows разных версий. Каждый из этих форматов имеет собственную сигнатуру. Например, для EXE-файлов современной Windows используется сигнатура 'PE'.

[11] Использование слова «nice» – «приятный, любезный, благовоспитанный, изящный» в данном контексте обычно объясняют так: этот процесс настолько любезен, что уступает всем дорогу.

[12] Опыт подсказывает, что как только компьютеры с памятью в несколько гигабайт станут обычными, появятся и программы, способные найти более или менее полезное употребление всей этой памяти.



Поделиться:


Последнее изменение этой страницы: 2017-02-05; просмотров: 438; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.191.211.66 (0.034 с.)