Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Конспект лекций СПО 31-8-13.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
969.73 Кб
Скачать

1.4.4. Разделы в виртуальном адресном пространстве процесса

Адресное пространство процесса Windows

Адресное пространство процесса разделено на системный и пользовательский разделы – см. рис. 2- 27.

Ядро Windows

Драйверы

Системные

таблицы

Системные DLL

Пользовательские

DLL

Данные

Приложения

Рисунок 1 – 27 – разделы в адресном пространстве процесса Windows

В Win32 определены четыре механизма управления виртуальной памятью:

  • виртуальная память, используемая для операций с большими массивами объектов или структур (размер массива превышает размер страницы). Для реализации метода используется резервирование регионов в адресном пространстве процесса и последующая передача физической памяти региону;

  • кучи (heaps), применяемые для операций с большим количеством малых объектов (размер объекта меньше размера страницы);

  • файлы, проецируемые в память - средства для операций с файлами большого размера и для обеспечения совместного доступа приложений к данным;

  • AWE (Adressing Windowing Extension) – отображение виртуального адресного пространства на окно размером 4 Гб физической памяти, размер которой превышает 4 Гб.

Резервирование регионов в адресном пространстве процесса и передача физической памяти региону

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

Приложение резервирует регион в адресном пространстве процесса, используя функцию

VirtualAlloc(lpvAddress: Pointer; dwSize, flAllocationType, flProtect: DWORD): Pointer;

Первый параметр определяет положение резервируемого региона в адресном пространстве. Если параметр равен Nil, система определяет положение региона самостоятельно. Регионы всегда резервируются на границе 64К.

Если запрос выполнен, функция возвращает базовый адрес зарезервированного региона.

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

Третий параметр определяет вид операции – MEM_RESERVE – зарезервировать регион, MEM_COMMIT - передать региону физическую память (сначала нужно зарезервировать регион, затем передать ему память).

При указании параметра MEM_TOP_DOWN система размещает регион по максимально возможному адресу - Allocates memory at the highest possible address. Это дает возможность уменьшить фрагментацию виртуального адресного пространства.

В принципе можно одновременно зарезервировать регион и передать ему физическую память – например

VirtualAlloc (Nil, 100*1024, MEM_RESERVE OR MEM_COMMIT, PAGE_READWRITE);

Последний параметр определяет атрибут защиты.

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

VirtualFree (lpAddress: Pointer; dwSize,: DWORD): BOOL;

В простейшем случае использования этой функции – для освобождения всей переданной региону физической памяти – в параметр lpAddress необходимо передать базовый адрес региона, в параметр dwSize=0, так как системе известен размер региона. В третьем параметре следует передать MEM_RELEASE – это приведет к возврату системе всей физической памяти, спроецированной на регион, и освобождению самого региона. Если необходимо не освобождая регион вернуть в систему часть физической памяти, переданной региону, в параметр lpAddress заносится адрес, идентифицирующий первую возвращаемую страницу, в параметр dwSize – количество возвращаемых байт, в параметре dwFreeType - MEM_DECOMMIT.

Файлы, проецируемые в память

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

Описанный механизм управления памятью применяется для:

  • загрузки и исполнения EXE- и DLL-файлов. Это позволяет существенно экономить как на размере страничного файла, так и на времени, необходимом системе для подготовки приложения к исполнению;

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

  • обеспечения совместного доступа разных процессов к общим данным.

Подготовка к использованию файлов, проецируемых в память

Для этого нужно выполнить три операции:

  1. Создать или открыть объект ядра "файл".

  2. Создать объект ядра "проецируемый файл", чтобы сообщить системе размер файла и способ доступа к нему.

  3. Указать системе, как спроецировать в адресное пространство процесса созданный в п.2 объект - целиком или только его часть.

Для завершения работы с файлом, проецируемым в память, следует выполнить три операции:

  1. Сообщить системе об отмене проецирования на адресное пространство процесса объекта ядра "проецируемый файл".

  2. Закрыть этот объект.

  3. Закрыть объект ядра "файл".

Создание и использование куч

Процессу разрешено создавать несколько куч, являющихся частью его адресного пространства.

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

Одна куча предоставляется процессу по умолчанию. Ее описатель возвращает функция

GetProcessHeap() : Handle;

Дополнительные кучи создаются вызовом функции

HeapCreate ( flOption, dwInitialSize, MaximumSize) : Handle;

Первый параметр определяет характер операций, выполняемых над кучей. По умолчанию (значение 0) действует принцип последовательного доступа к куче (как к критическому участку).

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

Третий параметр указывает максимальный размер кучи. Может быть равен 0 - в этом случае система резервирует регион, самостоятельно определяя его размер и при необходимости расширяет его до максимально возможного объема.

Выделение блока памяти из кучи выполняет функция

HeapAlloc ( Handle, dwFlags, dwBytes ) : pointer;

Первый параметр - описатель кучи, возвращаемый функциями GetProcessHeap() или HeapCreate()

Второй параметр указывает на характер выделения памяти. При его значении, равным HEAP_ZERO_MEMORY=8, выделяемый блок заполняется нулями.

Третий параметр определяет число выделяемых в куче байт.

Освобождение блока памяти выполняет функция

HeapFree ( Handle, dwFlags, dwBytes ) : Boolean;

Уничтожение кучи выполняет функция HeapDestroy (Handle) : Boolean.

Получение информации о состояниии виртуальной памяти

Сведения о конкретной платформе предоставляет процедура:

void GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)

Структура данных SYSTEM_INFO описана cледующим образом:

typedef struct _SYSTEM_INFO {

union {

DWORD dwOemId; struct {

WORD wProcessorArchitecture;

WORD wReserved;

};

};

DWORD dwPageSize;

LPVOID lpMinimumApplicationAddress;

LPVOID lpMaximumApplicationAddress;

DWORD_PTR dwActiveProcessorMask;

DWORD dwNumberOfProcessors;

DWORD dwProcessorType;

DWORD dwAllocationGranularity;

WORD wProcessorLevel;

WORD wProcessorRevision;

} SYSTEM_INFO

Более подробная информация приведена в MSDN.

Для динамического отслеживания текущего состояния памяти используется процедура

void GlobalMemoryStatus(

LPMEMORYSTATUS lpBuffer

);

Структура данных _MEMORYSTATUS описана как

typedef struct _MEMORYSTATUS { DWORD dwLength;

DWORD dwMemoryLoad;

SIZE_T dwTotalPhys;

SIZE_T dwAvailPhys;

SIZE_T dwTotalPageFile;

SIZE_T dwAvailPageFile;

SIZE_T dwTotalVirtual;

SIZE_T dwAvailVirtual;

} MEMORYSTATUS,

*LPMEMORYSTATUS

Назначение полей данной структуры:

dwMemoryLoad - оценка занятости системы управления памятью(0-100)

dwTotalPhys - общий размер физической памяти RAM-памяти в байтах

dwAvailPhys - общий размер физической памяти RAM-памяти в байтах, доступной для выделения

dwTotalPageFile - максимальное количество байтов, которое может содержаться в страничном файде на жестком диске (или дисках)

dwAvailPageFile - максимальное количество байтов, которое может быть передано процессу из страничного файла

dwTotalVirtual: DWORD - количество байтов в адресном пространстве, принадлежащих лично данному процессу

dwAvailVirtual - суммарный объем всех свободных регионов в адресном пространстве процесса, вызывающего процедуру GlobalMemoryStatus

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

Перед вызовом процедуры необходимо занести в поле dwLength размер структуры в байтах с помощью функции sizeof().

Для запроса информации об участке памяти по заданному адресу (размер, тип памяти, атрибуты защиты) текущего процесса служит функция:

SIZE_T VirtualQuery(

LPCVOID lpAddress,

PMEMORY_BASIC_INFORMATION lpBuffer,

SIZE_T dwLength

);

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

Второй параметр – переменная типа, описанного как

typedef struct _MEMORY_BASIC_INFORMATION { PVOID BaseAddress; PVOID AllocationBase; DWORD AllocationProtect; SIZE_T RegionSize; DWORD State; DWORD Protect; DWORD Type;

} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;

Назначение полей данной структуры:

BaseAddress - значение параметра lpAddress, округленное до значения, кратного размеру страницы

AllocationBase - базовый адрес региона, включающего адрес запроса

AllocationProtect - атрибут защиты региона – некоторые из возможных значений PAGE_NOACCESS, PAGE_READONLY, PAGE_READWRITE

RegionSize - суммарный размер (в байтах) группы страниц, начинающихся с базового адреса и имеющих те же атрибуты защиты, состояние и тип, что и страница, обнаруженная по адресу lpAddress

State - указывает состояние (MEM_FREE, MEM_RESERVE, MEM_COMMIT) всех смежных страниц, имеющих те же атрибуты защиты, состояние и тип, что и страница, расположенная по адресу lpAddress

Для состояния MEM_FREE элементы Allocationbase, Alloocation, Protect и Type не определяются

Protect - содержит атрибут защиты (PAGE_*),общий для всех смежных страниц, имеющих те же атрибуты защиты, состояние и тип, что и страница, расположенная по адресу lpAddress

Type - определяет тип физической памяти (MEM_IMAGE, MEM_MAPPED или MEM_PRIVATE), связанной с группой смежных страниц, имеющих имеющих те же атрибуты защиты,состояние и тип, что и страница, расположенная по адресу lpAddress

Параметр dwLength задает размер структуры MEORY_BASIC_INFORMATION.

Функция VirtualQuery() возвращает число байт, скопированных в буфер. Если возвращено нулевое значение, информация о запрошенном участке НЕ ПОЛУЧЕНА.

Сканируя память в диапазоне от минимального до максимального адреса, можно построить карту виртуальной памяти процесса.

Тема 1.5. Статическое и динамическое связывание. Динамически подключаемые библиотеки (DLL)

Статическое и динамическое связывание

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

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

От написания до выполнения программа проходит следующие этапы:

  • Трансляция

  • Редактирование связей (компоновка)

  • Загрузка.

На рисунке 1 -28 показаны перечисленные этапы и используемые для их выполнения системные обрабатывающие программы.

Рисунок 1-28- этапы подготовки и выполнения прикладной программы

Программа пишется в виде исходного модуля, на рисунке - файл ИМ.

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

Трансляция - преобразование программы, представленной на одном языке программирования, в программу на другом языке программирования, в определенном смысле равносильную первой.

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

Трансляторы - общее название для программ, осуществляющих трансляцию. Они подразделяются на Ассемблеры и Компиляторы - в зависимости от исходного языка программы, которую они обрабатывают.

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

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

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

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

Загрузочный модуль - программный модуль, представленный в форме, пригодной для загрузки в оперативную память для выполнения.

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

Описанный процесс называется статическим связыванием.

Статическое связывание использовалось в однозадачных ОС. В многозадачных ОС (к которым относится и MS Windows) статическое связывание приводит к неэффективному использованию ОП, и вместо него используется динамическое связывание, основанное на использовании динамически связываемых (подключаемых) библиотек – DLL – dynamic linked libraries. В этом случае редактирование связей выполняется при каждом запуске программы на выполнение и совмещается с загрузкой. Этот вариант связывания при запуске более расходный, т.к. затраты на связывание тиражируются при каждом запуске. Но он обеспечивает:

  • большую гибкость в сопровождении, так как позволяет менять отдельные объектные модули программы, не меняя остальных модулей;

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