Диспетчер памяти отслеживает использование закрытой переданной памяти на глобальном уровне и по каждому процессу отдельно (в виде квоты страничного файла). И вновь эти данные отражают не размер использованного пространства в страничном файле, а объем переданной закрытой памяти. Соответствующие счетчики увеличиваются при передаче виртуальных адресов, требующих новых закрытых физических страниц. Как только система достигнет глобального лимита на переданную память (т. е. физическая память и страничные файлы заполнены), попытки выделения виртуальной памяти будут заканчиваться неудачно – пока какой-либо процесс не освободит переданную ему память (например, после завершения).
   При загрузке системы процесс диспетчера сеансов (см. главу 4) считывает список страничных файлов, которые он должен открыть. Этот список хранится в параметре реестра HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PagingFiles. Этот многострочный параметр содержит имя, минимальный и максимальный размеры каждого страничного файла. Windows поддерживает до 16 страничных файлов. B х86-системах с обычным ядром каждый страничный файл может быть размером до 4095 Мб, в x64- и х86-системах с РАЕ-ядром – до 16 Тб, а в IА64-системах – до 32 Тб. Страничные файлы нельзя удалить во время работы системы, так как процесс System (см. главу 2) открывает описатель каждого страничного файла. Тот факт, что страничные файлы открываются системой, объясняет, почему встроенное средство дефрагментации не в состоянии дефрагментировать страничный файл в процессе работы системы. Для дефрагментации страничного файла используйте бесплатную утилиту Pagedefrag .B ней применяется тот же подход, что и в других сторонних утилитах дефрагментации: она запускает свой процесс дефрагментации на самом раннем этапе загрузки системы, еще до открытия страничных файлов диспетчером сеансов.
   Поскольку страничный файл содержит части виртуальной памяти процессов и ядра, для большей безопасности его можно настроить на очистку при выключении системы. Для этого установите параметр реестра HKLM\SYSTEM \CurrentControlSet\Control\Session Manager\Memory Management\ClearPageFile-AtShutdown в 1. Иначе в страничном файле останутся те данные, которые были выгружены в него к моменту выключения системы. И к этим данным сможет обратиться любой, кто получит физический доступ к компьютеру.
   Если не указано ни одного страничного файла, Windows 2000 создает в загрузочном разделе 20-мегабайтный страничный файл. Windows XP и Windows Server 2003 не создают этот временный страничный файл, и поэтому в такой ситуации объем системной виртуальной памяти будет ограничен доступной физической памятью. Windows XP и Windows Server 2003, если минимальный и максимальный размеры страничного файла заданы нулевыми, считают, что этот файл управляется системой, и его размер выбирается в соответствии с данными, показанными в таблице 7-14.
 
    ЭКСПЕРИМЕНТ: просмотр страничных файлов
   Как уже говорилось, список страничных файлов хранится в параметре реестра HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\ Memory Management\PagingFiles. Он содержит конфигурационные параметры страничных файлов, которые модифицируются через апплет System (Система) в Control Panel (Панель управления). B Windows 2000 щелкните кнопку Performance Options (Параметры быстродействия) на вкладке Advanced (Дополнительно) и нажмите кнопку Change (Изменить). B Windows XP и Windows Server 2003 откройте вкладку Advanced (Дополнительно), щелкните кнопку Settings (Параметры) в разделе Performance (Быстродействие), откройте еще одну вкладку Advanced (Дополнительно) и, наконец, нажмите кнопку Change (Изменить) в разделе Virtual Memory (Виртуальная память).
   Создать новый страничный файл можно через Control Panel. При этом вызывается системный сервис NtCreatePagingFile,определенный в Ntdll.dll и предназначенный только для внутреннего использования. Страничные файлы всегда создаются несжатыми, даже если находятся в сжатом каталоге. Для защиты новых страничных файлов от удаления их описатели дублируются в процесс System.
   B таблице 7-15 перечислены счетчики производительности, с помощью которых можно исследовать использование переданной закрытой памяти в рамках как всей системы, так и каждого страничного файла. K сожалению, определить соотношение резидентной и нерезидентной (находящейся в страничном файле) частей закрытой памяти, которая передана какому-либо процессу, нельзя.
   Заметьте, что эти счетчики могут помочь в подборе размера страничного файла. Исходить из объема оперативной памяти (RAM) нет смысла: чем больше у вас памяти, тем меньше вероятность того, что вам понадобится выгрузка данных на диск. Чтобы определить, какой размер страничного файла действительно нужен в вашей системе с учетом используемых вами приложений, проверьте пиковое значение переданной памяти, которое отображается в разделе Commit Charge (Выделение памяти) на вкладке Performance
   (Быстродействие) диспетчера задач, а также в окне System Information утилиты Process Explorer. Этот показатель отражает пиковый объем страничного файла с момента загрузки системы, который понадобился бы в том случае, если бы системе пришлось выгрузить всю закрытую переданную виртуальную память (что происходит крайне редко).
   Если страничный файл в вашей системе слишком велик, Windows не будет использовать лишнее пространство; иначе говоря, увеличение размера страничного файла не изменит производительность системы – просто у нее будет больше неразделяемой (non-shareable) переданной виртуальной памяти. Ho если страничный файл слишком мал для запускаемого вами набора приложений, может появиться сообщение об ошибке «system running low on virtual memory» (в системе не хватает виртуальной памяти). B таком случае сначала проверьте, не дает ли какой-нибудь процесс утечки памяти. Для этого посмотрите на счетчики байтов закрытой памяти для процессов в столбце VM Size (Объем виртуальной памяти) на вкладке Processes (Процессы) диспетчера задач. Если ни один из процессов вроде бы не дает утечки памяти, проделайте операции, описанные в эксперименте «Анализ утечки памяти в пуле» ранее в этой главе.
 
    ЭКСПЕРИМЕНТ: наблюдаем за использованием страничного файла через диспетчер задач
   Вы можете узнать, как используется переданная память, и с помощью Task Manager (Диспетчер задач), открыв в нем вкладку Performance (Быстродействие). При этом вы увидите следующие счетчики, связанные со страничными файлами.
   Заметьте, что график Mem Usage, который в Windows XP и Windows Server 2003 называется PF Usage (Файл подкачки), на самом деле соответствует общему объему переданной системной памяти (system commit total). Это значение отражает потенциально возможное,а не реальное использование страничного файла. Как мы уже говорили, столько места в страничном файле понадобилось бы в том случае, если бы системе вдруг пришлось выгрузить сразу всю закрытую переданную виртуальную память.
   Дополнительную информацию вы найдете в окне System Information утилиты Process Explorer.
 
Дескрипторы виртуальных адресов
   Момент загрузки страниц в память диспетчер памяти определяет, используя алгоритм подкачки по требованию (demand-paging algorithm). Страница загружается с диска, если поток, обращаясь к ней, вызывает ошибку страницы. Подобно копированию при записи подкачка по требованию является одной из форм отложенной оценки(lazy evaluation) – выполнения операции только при ее абсолютной необходимости.
   Диспетчер памяти использует отложенную оценку не только при загрузке страниц в память, но и при формировании таблиц, описывающих новые страницы. Например, когда поток передает память большой области виртуальной памяти с помощью VirtualAlloc,диспетчер памяти мог бы немедленно создать таблицы страниц, необходимые для доступа ко всему диапазону выделенной памяти. A что если часть этого диапазона останется невостребованной? Зачем впустую расходовать процессорное время? Вместо этого диспетчер памяти откладывает формирование таблицы страниц до тех пор, пока поток не вызовет ошибку страницы. Такой подход существенно увеличивает быстродействие процессов, резервирующих и/или передающих большие объемы памяти, но обращающихся к ней не очень часто.
   При использовании алгоритма отложенной оценки выделение даже больших блоков памяти происходит очень быстро. Когда поток выделяет память, диспетчер памяти должен соответственно отреагировать. Для этого диспетчер памяти поддерживает набор структур данных, которые позволяют вести учет зарезервированных и свободных виртуальных адресов в адресном пространстве процесса. Эти структуры данных называются дескрипторами виртуальных адресов(virtual address descriptors, VAD). Для каждого процесса диспетчер памяти поддерживает свой набор VAD, описывающий состояние адресного пространства этого процесса. Для большей эффективности поиска VAD организованы в виде двоичного дерева с автоматической балансировкой. B Windows Server 2003 реализован алгоритм дерева AVL (это первые буквы фамилий его разработчиков – Adelson-Velskii и Landis), который обеспечивает более эффективную балансировку VAD-дерева, а это уменьшает среднее число операций сравнения при поиске VAD, соответствующего некоему виртуальному адресу. Схема дерева VAD показана на рис. 7-28.
   Когда процесс резервирует адресное пространство или проецирует представление раздела, диспетчер памяти создает VAD для хранения информации из запроса на выделение – диапазона резервируемых адресов, его типа (разделяемый или закрытый), возможности наследования содержимого диапазона дочерними процессами, атрибутов защиты, установленных для страниц этого диапазона.
   При первом обращении потока по какому-либо адресу диспетчер памяти должен создать PTE страницы, содержащей данный адрес. Для этого он находит VAD, чей диапазон включает нужный адрес, и использует его информацию для заполнения РТЕ. Если адрес выпадает из диапазонов VAD или находится в зарезервированном, но не переданном диапазоне адресов, диспетчер памяти узнает, что поток не выделил память до попытки ее использования, и генерирует нарушение доступа.
 
    ЭКСПЕРИМЕНТ: просмотр дескрипторов виртуальных адресов
   Чтобы просмотреть VAD для какого-либо процесса, используйте команду !vadотладчика ядра. Сначала найдите адрес корня VAD-дерева с помощью команды !process.Затем введите полученный адрес в команде !vad,как показано в примере для процесса, выполняющего Notepad.exe.
 
Объекты-разделы
   Вероятно, вы помните, что объект «раздел» (section object), в подсистеме Windows называемый объектом «проекция файла» (file mapping object), представляет блок памяти, доступный двум и более процессам для совместного использования. Объект-раздел можно проецировать на страничный файл или другой файл на диске.
   Исполнительная система использует разделы для загрузки исполняемых образов в память, а диспетчер кэша – для доступа к данным в кэшированном файле (подробнее на эту тему см. главу 11). Объекты «раздел» также позволяют проецировать файлы на адресные пространства процессов. При этом можно обращаться к файлу как к большому массиву, проецируя разные представления объекта-раздела и выполняя операции чтения-записи в памяти, а не в самом файле, – такие операции называются вводом-выводом в проецируемые файлы(mapped file I/O). Если программа обратится к недействительной странице (отсутствующей в физической памяти), возникнет ошибка страницы, и диспетчер памяти автоматически загрузит эту страницу в память из проецируемого файла. Если программа модифицирует страницу, диспетчер памяти сохранит изменения в файле в процессе обычных операций, связанных с подкачкой. (Приложение может самостоятельно сбросить представление файла на диск вызовом Windows-функции FlushViewOfFile)
   Как и другие объекты, разделы создаются и уничтожаются диспетчером объектов. Он создает и инициализирует заголовок объекта «раздел», а диспетчер памяти определяет тело этого объекта. Диспетчер памяти также реализует сервисы, через которые потоки пользовательского режима могут получать и изменять атрибуты, хранящиеся в теле объекта «раздел». Структура объекта «раздел» показана на рис. 7-29.
   Уникальные атрибуты, хранящиеся в объектах «раздел» перечислены в таблице 7-l6.
 
    ЭКСПЕРИМЕНТ: просмотр объектов «раздел»
   Утилита Object Viewer ^Winobj.exe с сайта www.sysintemals.com или Winobj.exe из Platform SDK) позволяет просмотреть список разделов с глобальными именами. Вы можете перечислить открытые описатели объектов «раздел» с помощью любых утилит, описанных в разделе «Диспетчер объектов» главы 3 и способных перечислять содержимое таблицы открытых описателей. (Как уже говорилось в главе 3, эти имена хранятся в каталоге диспетчера объектов \BaseNamedObjects.)
   Используя Process Explorer или Handles.exe ( wwwsysintemats.com ),либо утилиту Oh.exe (Open Handles) из ресурсов Windows, можно вывести список открытых описателей объектов «раздел». Например, следующая команда показывает все открытые описатели каждого объекта «раздел» независимо от того, есть ли у него имя. (Разделу должно быть присвоено имя, если другой процесс открывает его по имени.)
   Для просмотра проецируемых файлов можно воспользоваться и утилитой Process Explorer. Выберите из меню View команду Lower Pane View, а затем DLLs. Файлы в колонке ММ, помеченные звездочкой, являются проецируемыми (в отличие от DLL и других файлов, загружаемых загрузчиком образов в виде модулей). Вот пример:
   Структуры данных, поддерживаемые диспетчером памяти и описывающие проецируемые разделы, показаны на рис. 7-30. Эти структуры гарантируют согласованность данных, считанных из проецируемого файла, независимо от типа доступа.
   Каждому открытому файлу, представленному объектом «файл», соответствует структура указателей объекта «раздел»(section object pointers structure). Эта структура является ключевой для поддержания согласованности данных при всех типах доступа к файлу; она же используется и при кэшировании файлов. Структура указателей объекта «раздел» ссылается на одну или две области управления(control areas). Одна из них используется для проецирования файла при обращении к нему как к файлу данных, а другая – для проецирования файла при запуске его как исполняемого образа.
   Область управления в свою очередь указывает на структуры подраздела(subsection structures), содержащие информацию о проецировании каждого раздела файла (только для чтения, для чтения и записи, копирование при записи и т. д.). Область управления также ссылается на структуру сегмента(segment structure), которая создается в пуле подкачиваемой памяти и указывает на прототипные РТЕ, указывающие на реальные страницы, проецируемые объектом «раздел». Как уже говорилось, таблицы страниц процесса ссылаются на эти прототипные РТЕ, а те указывают на страницы, к которым происходит обращение.
   Хотя Windows гарантирует, что любой процесс, обращающийся к файлу (для чтения или записи), всегда имеет дело с согласованными данными, возможна одна ситуация, при которой в физической памяти могут находиться две копии страниц файла (но и в этом случае предоставляется только самая последняя копия и поддерживается согласованность данных). Такое дублирование происходит из-за обращения к файлу образа как к файлу данных (для чтения или записи) с его последующим запуском как исполняемого файла. Например, при сборке и последующем запуске файла образа компоновщик открывает его для доступа к данным, а при запуске программы загрузчик образов проецирует этот файл как исполняемый. При этом выполняются следующие операции.
 
   1. Если исполняемый образ был создан через API-функции проецирования файлов (или с помощью диспетчера кэша), создается и область управления для представления считываемых или записываемых страниц данных в этом файле.
   2. Когда запускается образ и создается объект «раздел» для проецирования образа как исполняемого, диспетчер памяти обнаруживает, что указатели объекта «раздел» для файла образа ссылаются на область управления данными, и сбрасывает этот раздел на диск. Эта операция нужна для того, чтобы гарантировать сохранение любых модифицированных страниц на диске до обращения к образу через область управления кодом.
   3. Диспетчер памяти создает область управления кодом.
   4. Как только начинается выполнение образа, обращение к страницам его файла (доступным только для чтения) вызывает ошибки страниц, и они загружаются в память.
 
   Поскольку страницы, проецируемые областью управления данными, все еще могут быть резидентными (в списке простаивающих страниц), эта ситуация является одним из примеров существования двух копий одних и тех же данных на разных страницах памяти. Ho такое дублирование не нарушает согласованность данных, поскольку область управления данными уже сброшена на диск, а значит, страницы, считанные из файла, содержат последние данные (причем эти страницы никогда не записываются обратно на диск).
 
    ЭКСПЕРИМЕНТ: просмотр областей управления
   Чтобы найти адрес структур областей управления, вы должны сначала найти адрес нужного объекта «файл». Его можно получить с помощью отладчика ядра, создав командой !handleдамп таблицы описателей, принадлежащей процессу. Хотя команда !fileотладчика ядра сообщает основные сведения об объекте «файл», она не дает указатель на структуру указателей объекта «раздел». Затем, используя команду dt,отформатируйте объект «файл», чтобы получить адрес структуры указателей объекта «раздел». Эта структура состоит из трех указателей: на область управления данными, на разделяемую проекцию кэша (см. главу 11) и на область управления кодом. Получив адрес нужной области управления (если она есть) из структуры указателей объекта «раздел», укажите его как аргумент в команде !ca.
   Скажем, если вы откроете файл PowerPoint и выведете таблицу описателей для этого процесса командой !handle,то найдете открытый описатель файла PowerPoint, как показано ниже. (Об использовании команды !handleсм. раздел «Диспетчер объектов» главы 3.)
   Затем, сделав то же самое, но применительно к адресу структуры указателей объекта «раздел» (0x85512fec), вы получите:
   Наконец, команда !caпокажет вам область управления по этому адресу:
   Другой метод – применение команды !memusage.Ниже приведен фрагмент вывода этой команды.
   Значения в колонке Control указывают на структуру области управления, описывающую проецируемый файл. Вы можете просмотреть области управления, сегменты и подразделы с помощью команды !caотладчика ядра. Например, чтобы получить дамп области управления для проецируемого файла Winword.exe, введите команду !caи укажите в ней число из колонки Control, как показано ниже.
 
Рабочие наборы
   Здесь мы сосредоточимся на виртуальной части Windows-процесса – таблицах страниц, PTE и VAD. B оставшейся части главы мы расскажем, как Windows хранит в физической памяти подмножество виртуальных адресов.
   Как вы помните, подмножество виртуальных страниц, резидентных в физической памяти, называется рабочим набором(working set). Существует три вида рабочих наборов:
    (o)процесса – содержит страницы, на которые ссылаются его потоки;
    (o)системы – содержит резидентное подмножество подкачиваемого системного кода (например, Ntoskrnl.exe и драйверов), пула подкачиваемой памяти и системного кэша;
    (o)сеанса – в системах с включенной службой Terminal Services каждый сеанс получает свой рабочий набор. Он содержит резидентное подмножество специфичных для сеанса структур данных режима ядра, создаваемых частью подсистемы Windows, которая работает в режиме ядра (Win32k.sys), пула подкачиваемой памяти сеанса, представлений, проецируемых в сеансе, и других драйверов устройств, проецируемых на пространство сеанса. Прежде чем детально рассматривать каждый тип рабочего набора, обсудим общие правила выбора страниц, загружаемых в память, и определения срока их пребывания в физической памяти.
 
Подкачка по требованию
   Диспетчер памяти Windows использует алгоритм подкачки по требованию с кластеризацией. Когда поток вызывает ошибку страницы, диспетчер памяти загружает не только страницу, при обращении к которой возникла ошибка, но и несколько предшествующих и/или последующих страниц. Эта стратегия обеспечивает минимизацию числа операций ввода-вывода, связанных с подкачкой. Поскольку программы (особенно большие) в любой момент времени обычно выполняются в небольших областях своего адресного пространства, загрузка виртуальных страниц кластерами уменьшает число операций чтения с диска. При ошибках, связанных со ссылками на страницы данных в образах, размер кластера равен 3, в остальных случаях – 7.
   Однако политика подкачки по требованию может привести к тому, что какой-то процесс будет вызывать очень много ошибок страниц в момент начала выполнения его потоков или позднее при возобновлении их выполнения. Для оптимизации запуска процесса (и системы) в Windows XP и Windows Server 2003 введен механизм интеллектуальной предвыборки (intelligent prefetch engine), также называемый средством логической предвыборки (logical prefetcher); о нем мы рассказываем в следующем разделе.
 
Средство логической предвыборки
   B ходе типичной загрузки системы или приложения порядок ошибок страниц таков, что некоторые страницы запрашиваются из одной части файла, затем из совсем другой его части, потом из другого файла и т. д. Такие скачкообразные переходы значительно замедляют каждую операцию доступа, и, как показывает анализ, время поиска на диске становится доминирующим фактором, который негативно сказывается на скорости загрузки системы и приложений. Предварительная выборка целого пакета страниц позволяет упорядочить операции доступа без лишнего «рыскания» по диску и тем самым ускорить запуск системы и приложений. Нужные страницы могут быть известны заранее благодаря высокой степени корреляции операций доступа при загрузках системы или запусках приложений.
   Средство предвыборки, впервые появившееся в Windows XP, пытается ускорить загрузку системы и запуск приложений, отслеживая данные и код, к которым происходит обращение при этих процессах, и используя полученную информацию при последующих загрузке системы и запуске приложений для заблаговременного считывания необходимых кода и данных. Когда средство предвыборки активно, диспетчер памяти уведомляет код средства предвыборки в ядре об ошибках страниц – как аппаратных (требующих чтения данных с диска), так и программных (требующих простого добавления данных, которые уже находятся в памяти, в рабочий набор процесса). Средство предвыборки ведет мониторинг первых 10 секунд процесса запуска приложения. B случае загрузки системы это средство по умолчанию ведет мониторинг в течение 30 секунд после запуска пользовательской оболочки (обычно Explorer), или 60 секунд по окончании инициализации всех Windows-сервисов, или просто в течение 120 секунд – в зависимости от того, какое из этих трех событий произойдет первым.
   Собрав трассировочную информацию об ошибках страниц, организованную в виде списка обращений к файлу метаданных NTFS MFT (Master FiIe Table) (если приложение пыталось получить доступ к файлам или каталогам на NTFS-томах), а также списка ссылок на файлы и каталоги, код средства предвыборки, работающий в режиме ядра, уведомляет компонент предвыборки в службе Task Scheduler (Планировщик заданий) (\Windows\System32\Schedsvc.dll) и с этой целью переводит в свободное состояние объект-событие с именем PrefetchTracesReady.
 
    ПРИМЕЧАНИЕ Включить или отключить предвыборку при загрузке системы и/или запуске приложений позволяет DWORD-параметр реестра HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters\EnablePrefetcher: 0 – полное отключение предвыборки, 1 – предвыборка разрешена только при запуске приложений, 2 – предвыборка разрешена только при загрузке системы и 3 – предвыборка разрешена как при загрузке системы, так и при запуске приложений.
 
   Когда событие PrefetchTracesReadyпереводится в свободное состояние, Task Scheduler вызывает внутрисистемную функцию NtQuerySystemInformation,запрашивая через нее трассировочные данные. После дополнительной обработки этих данных Task Scheduler записывает их в файл, помещаемый в каталог \Windows\Prefetch фис. 7-31). Файлу присваивается имя, формируемое из имени приложения, к которому относятся трассировочные данные, дефиса и шестнадцатеричного представления хэша, полученного из строки пути к файлу. Затем к имени добавляется расширение .pf. Например, для Notepad создается файл NOTEPAD.EXE-AF43252301.PF.
   B этом правиле есть два исключения. Первое относится к образам, которые служат хостами других компонентов, в том числе к Microsoft Management Console ( \Windows\System32\Mmc.exe) и Dllhost (\Windows\System32\ Dllhost.exe). Поскольку в командной строке запуска этих приложений указываются дополнительные компоненты, средство предвыборки включает командную строку в генерируемый хэш. Таким образом, запуск таких приложений с другими компонентами в командной строке даст другой набор трассировочных данных. Средство предвыборки считывает список исполняемых образов, которые оно должно обрабатывать таким способом, из параметра HostingAppList в разделе реестра HKLM\System\CurrentControlSet\ Control\Session Manager\Memory Management\PrefetchParameters.