После знакомства со структурой виртуального адресного пространства перейдем к рассмотрению вопросов связывания виртуальных адресов с физическими адресами в рамках сегментно-
(рис 10.1) Трансляция адреса в страничной виртуальной схемеНа рис 10.1 представлено отображение различных типов виртуальных адресов в физические. Для трансляции виртуального адреса, сгенерированного процессором, нужно определить номер
Каждая строка в таблице страниц называется PTE (page
(рис 10.2) Структура строки таблицы страниц (PTE)Назначение отдельных атрибутов ясно из рисунка. Например, информация об обращении к странице или ее модификации (биты 5 и 6) позволяет собирать статистику обращений к памяти, которую используют V называются "действительными", а соответствующая страница находится в оперативной памяти.
При сброшенном ). Помимо нужной страницы диспетчер на всякий случай загружает в память несколько, обычно от 1 до 8, соседних страниц, чтобы минимизировать количество обращений к диску (стратегия подкачки по требованию с кластеризацией).
В действительности трансляция происходит более сложно (см., например, ). Существенная часть записей PTE кэшируется в ассоциативной памяти (TLB регистрах) процессора. При этом таблицу страниц в силу ее большого объема конструируют из двух уровней: каталог таблиц страниц (page directory) и таблицы страниц (page table), см. рис 10.3.
(рис 10.3) Трансляция адреса с использованием ассоциативной памяти и двухуровневой таблицы страницРазмер таблицы страниц подобран таким образом, что она целиком заполняет одну страницу оперативной памяти - 4 Кб. Для быстрого нахождения таблицы страниц один из регистров процессора (CR3 в Intel) указывает на каталог таблиц страниц (page directory) данного процесса, который хранится по адресу 0хС0300000. Значение этого регистра входит в
Как уже было сказано в предыдущей лекции, при отображении файла в память образуется регион в виртуальной памяти, а также сопутствующий ему объект-раздел или объект-секция (section object). Как и другие объекты, объекты-разделы управляются диспетчером объектов. В случае возникновения ошибок страниц подкачка осуществляется из страниц проецируемого файла, а не из общесистемного файла выгрузки.
Для таких регионов формируется массив прототипных PTE, описывающих нахождение всех страниц этого фрагмента памяти. PTE таблицы страниц процесса, выполнившего отображение, ссылаются на прототипные PTE, как это показано на рис 10.4, и тоже считаются недействительными. Если при этом другой процесс выполнил отображение этого же файла, то PTE его таблицы тоже будут ссылаться на эти же самые прототипные PTE (см. рис 10.4). Таким образом,
(рис 10.4) Реализация разделяемого между двумя процессами региона проецируемого в память файлаИзменения, сделанные в данном фрагменте памяти одним процессом, будут сразу же "видны" другому процессу. Таким образом, наличие таблицы прототипных PTE обеспечивает когерентность разделяемой памяти.
Более того, если третий процесс открыл тот же самый файл для обычного ввода-вывода, то уже существующее отображение будут рассматриваться в качестве буфера кэша этого файла, доступ к которому будет осуществляться через ту же самую таблицу прототипных PTE. Таким образом, все три процесса будут работать с одной и той же версией файла.
Помимо обмена информацией между различными процессами, разделяемые страницы применяются также для передачи данных между пользовательской и ядерной частями
Рассмотрим текст двух программ first.c и second.c
#include <windows.h>
#include <stdio.h>
void main(void){
HANDLE hMapFile;
LPVOID lpMapAddress;
HANDLE hFile;
char * String;
hFile = CreateFile("MyFile.txt", // имя файла
GENERIC_READ | GENERIC_WRITE, // файл для чтения и записи
FILE_SHARE_READ| FILE_SHARE_WRITE,// режим совместного доступа
NULL, // защита по умолчанию
OPEN_EXISTING, // файл должен существовать
FILE_ATTRIBUTE_NORMAL, // атрибуты файла
NULL); // файл атрибутов
if (hFile == INVALID_HANDLE_VALUE) printf("Could not open file\n");
hMapFile = CreateFileMapping(hFile, // описатель отображаемого файла
NULL, // атрибуты защиты по умолчанию
PAGE_READWRITE, // режим доступа
0, // старшее двойное слово размера буфера
0, // младшее двойное слово размера буфера
"MyFileObject"); // имя объекта
if (hMapFile == NULL) printf("Could not create file-mapping object.\n");
lpMapAddress = MapViewOfFile(hMapFile, // описатель отображаемого файла
FILE_MAP_ALL_ACCESS, // режимы доступа
0, 0, // отображение файла с начала
0); // отображение целого файла
if (lpMapAddress == NULL) printf("Could not map view of file.\n");
String = (char *)lpMapAddress;
sprintf(String, "Hello, world");
getchar();
}
#include <windows.h>
#include <stdio.h>
void main(void){
HANDLE hMapFile;
LPVOID lpMapAddress;
HANDLE hFile;
char * String;
hFile = CreateFile("MyFile.txt", // имя файла
GENERIC_READ | GENERIC_WRITE, // файл для чтения и записи
FILE_SHARE_READ| FILE_SHARE_WRITE,// режим совместного доступа
NULL, // защита по умолчанию
OPEN_EXISTING, // файл должен существовать
FILE_ATTRIBUTE_NORMAL, // атрибуты файла
NULL); // файл атрибутов
if (hFile == INVALID_HANDLE_VALUE)
{
printf("Could not open file\n"); // process error
}
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, // разрешение чтения-записи
FALSE, // описатель не наследуется
"MyFileObject"); // имя объекта проецируемого файла
if (hMapFile == NULL) printf("Could not open Filemapping\n");
lpMapAddress = MapViewOfFile(hMapFile, // описатель отображаемого файла
FILE_MAP_ALL_ACCESS, // режимы доступа
0, 0, // отображение файла с начала
0); // отображение целого файла
if (lpMapAddress == NULL) printf("Could not map view of file.\n");
String = (char *)lpMapAddress;
printf("%s\n", String);
getchar();
}
Программа first создает в своем адресном пространстве буфер разделяемой памяти, а программа second отображает тот же самый буфер в свое адресное пространство. Затем программа first записывает в этот буфер текстовую строку, а программа second выводит ее содержимое на экран. Обе программы должны быть запущены из одного каталога с уже существующим файлом MyFile.txt. Для наглядности рекомендуется, чтобы длина файла была изначально больше длины строки "Hello, world".
Рекомендуется модифицировать предыдущую программу для передачи информации через фрагмент разделяемой памяти, спроецированной не в обычный файл, а в системную область выгрузки. Для этого в качестве параметра CreateFileMapping нужно указать INVALID_HANDLE_VALUE.
Физическая (в данном случае оперативная) память и внешняя память также описываются соответствующими структурами данных.
ОС Windows поддерживает до 4 Гб (некоторые версии и более) физической памяти. Память более 32 Мб считается "большой". Объем памяти можно посмотреть на вкладке "Быстродействие" диспетчера задач.
Информация о состоянии страниц физической памяти и их принадлежности процессам находится в базе данных
Страничные файлы в отличие от файлов, проецируемых в память, хранят только модифицированные страницы, которые по каким-либо причинам выгружены на диск. Страницы, содержащие тексты программ, отображаются в память непосредственно из исполняемых модулей и не хранятся в общесистемных файлах выгрузки.
Структура системных страничных файлов недокументирована. Известно, что в системе может быть до 16 страничных файлов. Информация о страничных файлах находится в разделе HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PagingFiles реестра, однако управление страничными файлами рекомендуется осуществлять через апплет "система" административной консоли управления. У каждого файла подкачки есть начальный и максимальный размер. С целью уменьшения вероятной фрагментации их создают максимального размера.
Полезную информацию об использовании страничных файлов можно получить, наблюдая за счетчиками на вкладке "Производительность", а также с помощью диспетчера задач. Например, счетчик "Page File Bytes" показывает общее число переданных страниц.
В результате
Согласно документации по ОС Windows, рабочим набором процесса называется совокупность SetProcessWorkingSet.
Если возникает страничная ошибка и рабочий набор процесса не превысил лимита (при слабой загруженности системы допускается даже превышение лимита), система выделяет ему еще один кадр в физической памяти. В противном случае ОС пытается заменять страницы в рабочем наборе этого процесса (локальный алгоритм замещения).
Эволюцию рабочего набора процесса можно "увидеть", наблюдая за счетчиками
Рассмотрим легкую модификацию программы DemoVM, добавив туда операцию записи одного байта на каждую страницу переданной памяти (программа DemoPageFaults.c).
#include <windows.h>
#include <stdio.h>
void main(void)
{
PVOID pMem = NULL;
int nPageSize = 4096;
int nPages = 200;
long SizeCommit = 0;
int i;
char * Ptr;
SizeCommit = nPages * nPageSize;
getchar();
pMem = VirtualAlloc(0, SizeCommit, MEM_RESERVE| MEM_COMMIT, PAGE_READWRITE);
if(pMem == NULL) printf("VirtualAlloc Error\n");
Ptr = (char *)pMem;
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
getchar();
pMem = VirtualAlloc(0, SizeCommit, MEM_RESERVE| MEM_COMMIT, PAGE_READWRITE);
if(pMem == NULL) printf("VirtualAlloc Error\n");
Ptr = (char *)pMem;
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
getchar();
pMem = VirtualAlloc(0, SizeCommit, MEM_RESERVE| MEM_COMMIT, PAGE_READWRITE);
if(pMem == NULL) printf("VirtualAlloc Error\n");
Ptr = (char *)pMem;
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
getchar();
pMem = VirtualAlloc(0, SizeCommit, MEM_RESERVE| MEM_COMMIT, PAGE_READWRITE);
if(pMem == NULL) printf("VirtualAlloc Error\n");
Ptr = (char *)pMem;
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
getchar();
}
Наращивание объема переданной памяти и размера рабочего набора будет происходить по нажатию клавиши "Enter". Посмотрим на поведение счетчика "Рабочее множество" для процессов DemoVM и DemoPageFaults. Несмотря на одинаковый объем переданной физической памяти, размеры рабочего набора сильно отличаются. У DemoVM он остается близким к нулю, тогда как у процесса DemoPageFaults идет заметное ступенчатое приращение рабочего набора (см. рис 10.5)
(рис 10.5) Наблюдение за изменениями рабочих наборов процессовЗамещение страниц в рабочем наборе процесса - одна из наиболее ответственных операций. Дело в том, что уменьшение частоты page fault`ов является одной из ключевых задач системы управления памятью (например, известно, что вероятности page fault'а ).
В ОС Windows используются алгоритмы FIFO (first input first output) в многопроцессорном варианте и
В процессе функционирования операционной системы в физической памяти располагаются рабочие наборы процессов, системный рабочий набор, свободные фрагменты и многое другое. Для учета состояния физической памяти поддерживается база данных
Известно, что подсистема виртуальной памяти работает производительно при наличии резерва свободных страничных кадров. Тогда в случае страничной ошибки требуется только одна дисковая операция (чтение), и свободная страница может быть найдена немедленно. Алгоритмы, обеспечивающие поддержку системы в оптимальном состоянии, реализованы в составе
Формально, каждая страница физической памяти должна находиться в составе рабочего набора или входить в один из поддерживаемых базой связных списков страниц. Перемещение страниц между списками и рабочими наборами осуществляется системными потоками-демонами, входящими в состав менеджера памяти (см. ). Параметры настройки демонов хранятся в разделе HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management реестра
Чаще всего для обслуживания ошибки страницы в соответствии с требованиями защиты уровня C2 (см. часть V) требуется обнуленная страница, которая извлекается из соответствующего списка. Список обнуленных страниц пополняется потоком обнуления страниц (zero page thread) в фоновом режиме за счет списка свободных страниц. Иногда, например, для отображения файла, обнуленные страницы не нужны, и можно обойтись свободными страницами. Если у рабочего набора процесса отбирается страница, она попадает в список модифицированных страниц или в список свободных страниц. Подсистема записи модифицированных страниц (modified page writer) записывает их содержание на диск, когда количество таких страниц превышает установленный лимит. Страницы проецируемого файла можно сбросить на диск явным образом (при помощи функции FlushViewOfFile ). После записи модифицированная страница попадает в список свободных страниц.
Общее руководство и реализацию общих правил управления памятью осуществляет диспетчер рабочих наборов (
Количество ошибок страниц, генерируемых процессом, можно наблюдать при помощи счетчика "Ошибок страницы". На рис. приведены графики поведения счетчиков "Ошибок страниц" и "Рабочее множество" для процесса DempPageFaults. (см. программу, описанную выше)
(рис 10.6) Наблюдение за размером рабочего набора процесса и количеством страничных ошибокГрафики, приведенные на рис 10.6, показывают, что увеличение рабочего набора коррелирует с интенсивностью процессов подкачки внешней памяти.
При помощи утилиты Pfmon.exe из ресурсов Windows можно не только "увидеть" общее количество
… SOFT: RtlFillMemoryUlong+0x10 : 0x00232000 SOFT: RtlFillMemoryUlong+0x10 : 0x00233000 SOFT: GetConsoleInputWaitHandle+0x11a : GetConsoleInputWaitHandle+0x119 SOFT: FindFirstFileExA+0x285 : FindFirstFileExA+0x285 SOFT: main+0xe4 : 0x00440000 SOFT: main+0xe4 : 0x00441000 SOFT: main+0xe4 : 0x00442000 SOFT: main+0xe4 : 0x00443000 SOFT: main+0xe4 : 0x00444000 SOFT: main+0xe4 : 0x00445000 SOFT: main+0xe4 : 0x00446000 SOFT: main+0xe4 : 0x00447000 SOFT: main+0xe4 : 0x00448000 SOFT: main+0xe4 : 0x00449000 SOFT: main+0xe4 : 0x0044a000 SOFT: main+0xe4 : 0x0044b000 SOFT: main+0xe4 : 0x0044c000 SOFT: main+0xe4 : 0x0044d000 SOFT: main+0xe4 : 0x0044e000 SOFT: main+0xe4 : 0x0044f000 SOFT: main+0xe4 : 0x00450000 SOFT: main+0xe4 : 0x00451000 SOFT: main+0xe4 : 0x00452000 SOFT: main+0xe4 : 0x00453000 SOFT: main+0xe4 : 0x00454000 SOFT: main+0xe4 : 0x00455000 …
Корректная работа менеджера памяти помимо принципиальных вопросов, связанных с выбором абстрактной модели виртуальной памяти и ее аппаратной поддержкой, обеспечивается также множеством нюансов и мелких деталей.
Примером может служить локализация страниц в памяти, что означает временный запрет на выгрузку некоторых страниц, хранящих буферы ввода-вывода или другие важные данные и код, например, код и данные процессов реального времени.
По умолчанию, процессу разрешается блокировать максимум 30 страниц памяти. Если увеличить рабочее множество процесса при помощи функции SetProcessWorkingSetSize, то, согласно документации, максимальное число страниц, которое процесс может блокировать, равно минимальному размеру его рабочего набора за вычетом 8 страниц.
Локализация страниц в памяти осуществляется при помощи Win32 функции VirtualLock, а освобождение страниц - при помощи VirtualUnlock. Учет локализованных страниц ведется в страничной базе
Приведенный листинг является примером такой программы.
#include <windows.h>
#include <stdio.h>
void main(void)
{
PVOID pMem = NULL;
int nPageSize = 4096;
int nPages = 400;
int nPageLock = 100;
long SizeCommit = 0;
int i;
char * Ptr;
int nMinPages = 200, nMaxPages = 500;
long dwMinimumWorkingSetSize = 0, dwMaximumWorkingSetSize = 0;
HANDLE hProcess;
hProcess = GetCurrentProcess();
dwMinimumWorkingSetSize = nMinPages * nPageSize;
dwMaximumWorkingSetSize = nMaxPages * nPageSize;
i = SetProcessWorkingSetSize(hProcess, dwMinimumWorkingSetSize, dwMaximumWorkingSetSize);
if(i==0) printf("SetProcessWorkingSetSize Error\n");
SizeCommit = nPages * nPageSize;
pMem = VirtualAlloc(0, SizeCommit, MEM_RESERVE| MEM_COMMIT, PAGE_READWRITE);
if(pMem == NULL) printf("VirtualAlloc Error\n");
Ptr = (char *)pMem;
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
i = VirtualLock(pMem, nPageLock * nPageSize);
if(i==0) printf("VirtualLock Error\n");
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
VirtualUnlock(pMem, nPageLock * nPageSize);
VirtualFree(pMem, 0, MEM_RELEASE);
}
Другой нюанс в работе менеджера памяти, который можно проиллюстрировать на практике, связан с реализацией алгоритма отложенного выделения памяти - копирование при записи (copy-on-write). Это один из примеров алгоритма отложенной оценки (
Рассмотрим ситуацию, когда некоторая приватная область памяти процесса является точной копией уже существующего в системе фрагмента памяти. Например, память в Unix является копией памяти
Отложенное выделение памяти реализовано следующим образом. Отображаемые страницы помечаются флагом PAGE_WRITECOPY (доступные для чтения, но, в действительности, доступные для записи). Запись на такую страницу приводит к созданию ее приватной копии, которая и отображается на память. Теперь можно писать на эту страницу без риска изменить содержимое оригинальной страницы.
#include <windows.h>
#include <stdio.h>
void main(void)
{
HANDLE hMapFile;
LPVOID lpMapAddress;
HANDLE hFile;
char * String;
hFile = CreateFile("MyFile.txt",GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ| FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE) printf("Could not open file\n");
hMapFile = CreateFileMapping(hFile, NULL,
PAGE_WRITECOPY, // копирование при записи
0,0,"MyFileObject");
if (hMapFile == NULL) printf("Could not create file-mapping object.\n");
lpMapAddress = MapViewOfFile(hMapFile,
FILE_MAP_COPY, // копирование при записи
0,0,0);
if (lpMapAddress == NULL) printf("Could not map view of file.\n");
String = (char *)lpMapAddress;
getchar();
sprintf(String, "Hello, world");
printf("%s\n", String);
if (!UnmapViewOfFile(lpMapAddress)) printf("Could not unmap view of file.\n");
}
В приведенной программе часть страниц отображаемого файла помечена атрибутом PAGE_WRITECOPY. Запись текстовой строки в данный регион памяти осуществляется после нажатия клавиши "Enter". Рекомендуется осуществить прогон программы, наблюдая за счетчиком "запись копий страниц" при нажатии клавиши "Enter". Любопытно, что содержимое исходного файла при этом не меняется.
Изоляция адресных пространств различных процессов является базовой парадигмой современных ОС и обеспечивается путем прямой защиты памяти (атрибуты защиты) и косвенной защиты (механизм трансляции адреса). Вместе с тем, иногда возникают ситуации, когда доступ к памяти другого процесса все же необходим. В частности, эта возможность активно используется отладчиками.
Для доступа к памяти процесса нужно получить его описатель. Наиболее естественный способ получения описателя - получение описателя lProcessInformation функции CreateProcess.
Для создания регионов в памяти другого процесса можно использовать функцию VirtualAllocEx, которой нужно передать описатель этого процесса в качестве параметра. Для доступа к памяти другого процесса применяются функции ReadProcessMemory и WriteProcessMemory.
Рекомендуется самостоятельно написать программу, которая создает регион памяти в адресном пространстве
Базовой операцией менеджера памяти является трансляция виртуального адреса в физический с помощью таблицы страниц и ассоциативной (TLB) памяти. В ряде случаев, для реализации разделяемой памяти, интеграции с системой ввода-вывода и др., применяется прототипная таблица страниц, которая является промежуточным звеном между обычной таблицей страниц и физической памятью. Для описания страниц физической памяти поддерживается база данных
После знакомства со структурой виртуального адресного пространства перейдем к рассмотрению вопросов связывания виртуальных адресов с физическими адресами в рамках сегментно-
(рис 10.1) Трансляция адреса в страничной виртуальной схемеНа рис 10.1 представлено отображение различных типов виртуальных адресов в физические. Для трансляции виртуального адреса, сгенерированного процессором, нужно определить номер
Каждая строка в таблице страниц называется PTE (page
(рис 10.2) Структура строки таблицы страниц (PTE)Назначение отдельных атрибутов ясно из рисунка. Например, информация об обращении к странице или ее модификации (биты 5 и 6) позволяет собирать статистику обращений к памяти, которую используют V называются "действительными", а соответствующая страница находится в оперативной памяти.
При сброшенном ). Помимо нужной страницы диспетчер на всякий случай загружает в память несколько, обычно от 1 до 8, соседних страниц, чтобы минимизировать количество обращений к диску (стратегия подкачки по требованию с кластеризацией).
В действительности трансляция происходит более сложно (см., например, ). Существенная часть записей PTE кэшируется в ассоциативной памяти (TLB регистрах) процессора. При этом таблицу страниц в силу ее большого объема конструируют из двух уровней: каталог таблиц страниц (page directory) и таблицы страниц (page table), см. рис 10.3.
(рис 10.3) Трансляция адреса с использованием ассоциативной памяти и двухуровневой таблицы страницРазмер таблицы страниц подобран таким образом, что она целиком заполняет одну страницу оперативной памяти - 4 Кб. Для быстрого нахождения таблицы страниц один из регистров процессора (CR3 в Intel) указывает на каталог таблиц страниц (page directory) данного процесса, который хранится по адресу 0хС0300000. Значение этого регистра входит в
Как уже было сказано в предыдущей лекции, при отображении файла в память образуется регион в виртуальной памяти, а также сопутствующий ему объект-раздел или объект-секция (section object). Как и другие объекты, объекты-разделы управляются диспетчером объектов. В случае возникновения ошибок страниц подкачка осуществляется из страниц проецируемого файла, а не из общесистемного файла выгрузки.
Для таких регионов формируется массив прототипных PTE, описывающих нахождение всех страниц этого фрагмента памяти. PTE таблицы страниц процесса, выполнившего отображение, ссылаются на прототипные PTE, как это показано на рис 10.4, и тоже считаются недействительными. Если при этом другой процесс выполнил отображение этого же файла, то PTE его таблицы тоже будут ссылаться на эти же самые прототипные PTE (см. рис 10.4). Таким образом,
(рис 10.4) Реализация разделяемого между двумя процессами региона проецируемого в память файлаИзменения, сделанные в данном фрагменте памяти одним процессом, будут сразу же "видны" другому процессу. Таким образом, наличие таблицы прототипных PTE обеспечивает когерентность разделяемой памяти.
Более того, если третий процесс открыл тот же самый файл для обычного ввода-вывода, то уже существующее отображение будут рассматриваться в качестве буфера кэша этого файла, доступ к которому будет осуществляться через ту же самую таблицу прототипных PTE. Таким образом, все три процесса будут работать с одной и той же версией файла.
Помимо обмена информацией между различными процессами, разделяемые страницы применяются также для передачи данных между пользовательской и ядерной частями
Рассмотрим текст двух программ first.c и second.c
#include <windows.h>
#include <stdio.h>
void main(void){
HANDLE hMapFile;
LPVOID lpMapAddress;
HANDLE hFile;
char * String;
hFile = CreateFile("MyFile.txt", // имя файла
GENERIC_READ | GENERIC_WRITE, // файл для чтения и записи
FILE_SHARE_READ| FILE_SHARE_WRITE,// режим совместного доступа
NULL, // защита по умолчанию
OPEN_EXISTING, // файл должен существовать
FILE_ATTRIBUTE_NORMAL, // атрибуты файла
NULL); // файл атрибутов
if (hFile == INVALID_HANDLE_VALUE) printf("Could not open file\n");
hMapFile = CreateFileMapping(hFile, // описатель отображаемого файла
NULL, // атрибуты защиты по умолчанию
PAGE_READWRITE, // режим доступа
0, // старшее двойное слово размера буфера
0, // младшее двойное слово размера буфера
"MyFileObject"); // имя объекта
if (hMapFile == NULL) printf("Could not create file-mapping object.\n");
lpMapAddress = MapViewOfFile(hMapFile, // описатель отображаемого файла
FILE_MAP_ALL_ACCESS, // режимы доступа
0, 0, // отображение файла с начала
0); // отображение целого файла
if (lpMapAddress == NULL) printf("Could not map view of file.\n");
String = (char *)lpMapAddress;
sprintf(String, "Hello, world");
getchar();
}
#include <windows.h>
#include <stdio.h>
void main(void){
HANDLE hMapFile;
LPVOID lpMapAddress;
HANDLE hFile;
char * String;
hFile = CreateFile("MyFile.txt", // имя файла
GENERIC_READ | GENERIC_WRITE, // файл для чтения и записи
FILE_SHARE_READ| FILE_SHARE_WRITE,// режим совместного доступа
NULL, // защита по умолчанию
OPEN_EXISTING, // файл должен существовать
FILE_ATTRIBUTE_NORMAL, // атрибуты файла
NULL); // файл атрибутов
if (hFile == INVALID_HANDLE_VALUE)
{
printf("Could not open file\n"); // process error
}
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, // разрешение чтения-записи
FALSE, // описатель не наследуется
"MyFileObject"); // имя объекта проецируемого файла
if (hMapFile == NULL) printf("Could not open Filemapping\n");
lpMapAddress = MapViewOfFile(hMapFile, // описатель отображаемого файла
FILE_MAP_ALL_ACCESS, // режимы доступа
0, 0, // отображение файла с начала
0); // отображение целого файла
if (lpMapAddress == NULL) printf("Could not map view of file.\n");
String = (char *)lpMapAddress;
printf("%s\n", String);
getchar();
}
Программа first создает в своем адресном пространстве буфер разделяемой памяти, а программа second отображает тот же самый буфер в свое адресное пространство. Затем программа first записывает в этот буфер текстовую строку, а программа second выводит ее содержимое на экран. Обе программы должны быть запущены из одного каталога с уже существующим файлом MyFile.txt. Для наглядности рекомендуется, чтобы длина файла была изначально больше длины строки "Hello, world".
Рекомендуется модифицировать предыдущую программу для передачи информации через фрагмент разделяемой памяти, спроецированной не в обычный файл, а в системную область выгрузки. Для этого в качестве параметра CreateFileMapping нужно указать INVALID_HANDLE_VALUE.
Физическая (в данном случае оперативная) память и внешняя память также описываются соответствующими структурами данных.
ОС Windows поддерживает до 4 Гб (некоторые версии и более) физической памяти. Память более 32 Мб считается "большой". Объем памяти можно посмотреть на вкладке "Быстродействие" диспетчера задач.
Информация о состоянии страниц физической памяти и их принадлежности процессам находится в базе данных
Страничные файлы в отличие от файлов, проецируемых в память, хранят только модифицированные страницы, которые по каким-либо причинам выгружены на диск. Страницы, содержащие тексты программ, отображаются в память непосредственно из исполняемых модулей и не хранятся в общесистемных файлах выгрузки.
Структура системных страничных файлов недокументирована. Известно, что в системе может быть до 16 страничных файлов. Информация о страничных файлах находится в разделе HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PagingFiles реестра, однако управление страничными файлами рекомендуется осуществлять через апплет "система" административной консоли управления. У каждого файла подкачки есть начальный и максимальный размер. С целью уменьшения вероятной фрагментации их создают максимального размера.
Полезную информацию об использовании страничных файлов можно получить, наблюдая за счетчиками на вкладке "Производительность", а также с помощью диспетчера задач. Например, счетчик "Page File Bytes" показывает общее число переданных страниц.
В результате
Согласно документации по ОС Windows, рабочим набором процесса называется совокупность SetProcessWorkingSet.
Если возникает страничная ошибка и рабочий набор процесса не превысил лимита (при слабой загруженности системы допускается даже превышение лимита), система выделяет ему еще один кадр в физической памяти. В противном случае ОС пытается заменять страницы в рабочем наборе этого процесса (локальный алгоритм замещения).
Эволюцию рабочего набора процесса можно "увидеть", наблюдая за счетчиками
Рассмотрим легкую модификацию программы DemoVM, добавив туда операцию записи одного байта на каждую страницу переданной памяти (программа DemoPageFaults.c).
#include <windows.h>
#include <stdio.h>
void main(void)
{
PVOID pMem = NULL;
int nPageSize = 4096;
int nPages = 200;
long SizeCommit = 0;
int i;
char * Ptr;
SizeCommit = nPages * nPageSize;
getchar();
pMem = VirtualAlloc(0, SizeCommit, MEM_RESERVE| MEM_COMMIT, PAGE_READWRITE);
if(pMem == NULL) printf("VirtualAlloc Error\n");
Ptr = (char *)pMem;
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
getchar();
pMem = VirtualAlloc(0, SizeCommit, MEM_RESERVE| MEM_COMMIT, PAGE_READWRITE);
if(pMem == NULL) printf("VirtualAlloc Error\n");
Ptr = (char *)pMem;
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
getchar();
pMem = VirtualAlloc(0, SizeCommit, MEM_RESERVE| MEM_COMMIT, PAGE_READWRITE);
if(pMem == NULL) printf("VirtualAlloc Error\n");
Ptr = (char *)pMem;
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
getchar();
pMem = VirtualAlloc(0, SizeCommit, MEM_RESERVE| MEM_COMMIT, PAGE_READWRITE);
if(pMem == NULL) printf("VirtualAlloc Error\n");
Ptr = (char *)pMem;
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
getchar();
}
Наращивание объема переданной памяти и размера рабочего набора будет происходить по нажатию клавиши "Enter". Посмотрим на поведение счетчика "Рабочее множество" для процессов DemoVM и DemoPageFaults. Несмотря на одинаковый объем переданной физической памяти, размеры рабочего набора сильно отличаются. У DemoVM он остается близким к нулю, тогда как у процесса DemoPageFaults идет заметное ступенчатое приращение рабочего набора (см. рис 10.5)
(рис 10.5) Наблюдение за изменениями рабочих наборов процессовЗамещение страниц в рабочем наборе процесса - одна из наиболее ответственных операций. Дело в том, что уменьшение частоты page fault`ов является одной из ключевых задач системы управления памятью (например, известно, что вероятности page fault'а ).
В ОС Windows используются алгоритмы FIFO (first input first output) в многопроцессорном варианте и
В процессе функционирования операционной системы в физической памяти располагаются рабочие наборы процессов, системный рабочий набор, свободные фрагменты и многое другое. Для учета состояния физической памяти поддерживается база данных
Известно, что подсистема виртуальной памяти работает производительно при наличии резерва свободных страничных кадров. Тогда в случае страничной ошибки требуется только одна дисковая операция (чтение), и свободная страница может быть найдена немедленно. Алгоритмы, обеспечивающие поддержку системы в оптимальном состоянии, реализованы в составе
Формально, каждая страница физической памяти должна находиться в составе рабочего набора или входить в один из поддерживаемых базой связных списков страниц. Перемещение страниц между списками и рабочими наборами осуществляется системными потоками-демонами, входящими в состав менеджера памяти (см. ). Параметры настройки демонов хранятся в разделе HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management реестра
Чаще всего для обслуживания ошибки страницы в соответствии с требованиями защиты уровня C2 (см. часть V) требуется обнуленная страница, которая извлекается из соответствующего списка. Список обнуленных страниц пополняется потоком обнуления страниц (zero page thread) в фоновом режиме за счет списка свободных страниц. Иногда, например, для отображения файла, обнуленные страницы не нужны, и можно обойтись свободными страницами. Если у рабочего набора процесса отбирается страница, она попадает в список модифицированных страниц или в список свободных страниц. Подсистема записи модифицированных страниц (modified page writer) записывает их содержание на диск, когда количество таких страниц превышает установленный лимит. Страницы проецируемого файла можно сбросить на диск явным образом (при помощи функции FlushViewOfFile ). После записи модифицированная страница попадает в список свободных страниц.
Общее руководство и реализацию общих правил управления памятью осуществляет диспетчер рабочих наборов (
Количество ошибок страниц, генерируемых процессом, можно наблюдать при помощи счетчика "Ошибок страницы". На рис. приведены графики поведения счетчиков "Ошибок страниц" и "Рабочее множество" для процесса DempPageFaults. (см. программу, описанную выше)
(рис 10.6) Наблюдение за размером рабочего набора процесса и количеством страничных ошибокГрафики, приведенные на рис 10.6, показывают, что увеличение рабочего набора коррелирует с интенсивностью процессов подкачки внешней памяти.
При помощи утилиты Pfmon.exe из ресурсов Windows можно не только "увидеть" общее количество
… SOFT: RtlFillMemoryUlong+0x10 : 0x00232000 SOFT: RtlFillMemoryUlong+0x10 : 0x00233000 SOFT: GetConsoleInputWaitHandle+0x11a : GetConsoleInputWaitHandle+0x119 SOFT: FindFirstFileExA+0x285 : FindFirstFileExA+0x285 SOFT: main+0xe4 : 0x00440000 SOFT: main+0xe4 : 0x00441000 SOFT: main+0xe4 : 0x00442000 SOFT: main+0xe4 : 0x00443000 SOFT: main+0xe4 : 0x00444000 SOFT: main+0xe4 : 0x00445000 SOFT: main+0xe4 : 0x00446000 SOFT: main+0xe4 : 0x00447000 SOFT: main+0xe4 : 0x00448000 SOFT: main+0xe4 : 0x00449000 SOFT: main+0xe4 : 0x0044a000 SOFT: main+0xe4 : 0x0044b000 SOFT: main+0xe4 : 0x0044c000 SOFT: main+0xe4 : 0x0044d000 SOFT: main+0xe4 : 0x0044e000 SOFT: main+0xe4 : 0x0044f000 SOFT: main+0xe4 : 0x00450000 SOFT: main+0xe4 : 0x00451000 SOFT: main+0xe4 : 0x00452000 SOFT: main+0xe4 : 0x00453000 SOFT: main+0xe4 : 0x00454000 SOFT: main+0xe4 : 0x00455000 …
Корректная работа менеджера памяти помимо принципиальных вопросов, связанных с выбором абстрактной модели виртуальной памяти и ее аппаратной поддержкой, обеспечивается также множеством нюансов и мелких деталей.
Примером может служить локализация страниц в памяти, что означает временный запрет на выгрузку некоторых страниц, хранящих буферы ввода-вывода или другие важные данные и код, например, код и данные процессов реального времени.
По умолчанию, процессу разрешается блокировать максимум 30 страниц памяти. Если увеличить рабочее множество процесса при помощи функции SetProcessWorkingSetSize, то, согласно документации, максимальное число страниц, которое процесс может блокировать, равно минимальному размеру его рабочего набора за вычетом 8 страниц.
Локализация страниц в памяти осуществляется при помощи Win32 функции VirtualLock, а освобождение страниц - при помощи VirtualUnlock. Учет локализованных страниц ведется в страничной базе
Приведенный листинг является примером такой программы.
#include <windows.h>
#include <stdio.h>
void main(void)
{
PVOID pMem = NULL;
int nPageSize = 4096;
int nPages = 400;
int nPageLock = 100;
long SizeCommit = 0;
int i;
char * Ptr;
int nMinPages = 200, nMaxPages = 500;
long dwMinimumWorkingSetSize = 0, dwMaximumWorkingSetSize = 0;
HANDLE hProcess;
hProcess = GetCurrentProcess();
dwMinimumWorkingSetSize = nMinPages * nPageSize;
dwMaximumWorkingSetSize = nMaxPages * nPageSize;
i = SetProcessWorkingSetSize(hProcess, dwMinimumWorkingSetSize, dwMaximumWorkingSetSize);
if(i==0) printf("SetProcessWorkingSetSize Error\n");
SizeCommit = nPages * nPageSize;
pMem = VirtualAlloc(0, SizeCommit, MEM_RESERVE| MEM_COMMIT, PAGE_READWRITE);
if(pMem == NULL) printf("VirtualAlloc Error\n");
Ptr = (char *)pMem;
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
i = VirtualLock(pMem, nPageLock * nPageSize);
if(i==0) printf("VirtualLock Error\n");
for(i=0; i<nPages; i++) Ptr[i*nPageSize] = '0';
VirtualUnlock(pMem, nPageLock * nPageSize);
VirtualFree(pMem, 0, MEM_RELEASE);
}
Другой нюанс в работе менеджера памяти, который можно проиллюстрировать на практике, связан с реализацией алгоритма отложенного выделения памяти - копирование при записи (copy-on-write). Это один из примеров алгоритма отложенной оценки (
Рассмотрим ситуацию, когда некоторая приватная область памяти процесса является точной копией уже существующего в системе фрагмента памяти. Например, память в Unix является копией памяти
Отложенное выделение памяти реализовано следующим образом. Отображаемые страницы помечаются флагом PAGE_WRITECOPY (доступные для чтения, но, в действительности, доступные для записи). Запись на такую страницу приводит к созданию ее приватной копии, которая и отображается на память. Теперь можно писать на эту страницу без риска изменить содержимое оригинальной страницы.
#include <windows.h>
#include <stdio.h>
void main(void)
{
HANDLE hMapFile;
LPVOID lpMapAddress;
HANDLE hFile;
char * String;
hFile = CreateFile("MyFile.txt",GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ| FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE) printf("Could not open file\n");
hMapFile = CreateFileMapping(hFile, NULL,
PAGE_WRITECOPY, // копирование при записи
0,0,"MyFileObject");
if (hMapFile == NULL) printf("Could not create file-mapping object.\n");
lpMapAddress = MapViewOfFile(hMapFile,
FILE_MAP_COPY, // копирование при записи
0,0,0);
if (lpMapAddress == NULL) printf("Could not map view of file.\n");
String = (char *)lpMapAddress;
getchar();
sprintf(String, "Hello, world");
printf("%s\n", String);
if (!UnmapViewOfFile(lpMapAddress)) printf("Could not unmap view of file.\n");
}
В приведенной программе часть страниц отображаемого файла помечена атрибутом PAGE_WRITECOPY. Запись текстовой строки в данный регион памяти осуществляется после нажатия клавиши "Enter". Рекомендуется осуществить прогон программы, наблюдая за счетчиком "запись копий страниц" при нажатии клавиши "Enter". Любопытно, что содержимое исходного файла при этом не меняется.
Изоляция адресных пространств различных процессов является базовой парадигмой современных ОС и обеспечивается путем прямой защиты памяти (атрибуты защиты) и косвенной защиты (механизм трансляции адреса). Вместе с тем, иногда возникают ситуации, когда доступ к памяти другого процесса все же необходим. В частности, эта возможность активно используется отладчиками.
Для доступа к памяти процесса нужно получить его описатель. Наиболее естественный способ получения описателя - получение описателя lProcessInformation функции CreateProcess.
Для создания регионов в памяти другого процесса можно использовать функцию VirtualAllocEx, которой нужно передать описатель этого процесса в качестве параметра. Для доступа к памяти другого процесса применяются функции ReadProcessMemory и WriteProcessMemory.
Рекомендуется самостоятельно написать программу, которая создает регион памяти в адресном пространстве
Базовой операцией менеджера памяти является трансляция виртуального адреса в физический с помощью таблицы страниц и ассоциативной (TLB) памяти. В ряде случаев, для реализации разделяемой памяти, интеграции с системой ввода-вывода и др., применяется прототипная таблица страниц, которая является промежуточным звеном между обычной таблицей страниц и физической памятью. Для описания страниц физической памяти поддерживается база данных
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.