    АРХИТЕКТУРА ПАМЯТИ В WIN32 

    глава 5

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

    Виртуальное адресное пространство 

    В Win32 виртуальное адресное пространство каждого процесса составляет 4 
Гб. Соответственно 32-битный указатель может быть любым числом от 0х00000000 
до OxFFFFFFFF. Всего, таким образом, указатель может принимать 4 294 967 296 
значений, что как раз и перекрывает четырехгигабайтовый диапазон. 
    В MS-DOS и 16-разрядной Windows все процессы располагаются в едином 
адресном пространстве. Это значит, что один процесс может считывать и 
записывать в любом участке памяти, принадлежащем другому процессу, включая 
саму операционную систему. Поэтому любой процесс, естественно, оказывается 
зависим от поведения постороннего процесса. Если, например, процесс А случайно 
перезапишет данные, принадлежащие процессу В, тот перейдет в неустойчивое 
состояние и скорее всего просто рухнет. В отказоустойчивой операционной 
системе такого происходить не должно. 
    В среде Win32 эта проблема решается за счет того, что каждому процессу 
отводится закрытое адресное пространство. И когда в процессе выполняется 
какой-нибудь поток, он получает доступ только к той памяти, что принадлежит 
его процессу. Память, отведенная другим процессам, скрыта от этого потока и 
недоступна ему. 
    В Windows NT память, принадлежащая собственно операционной системе, скрыта 
от любого выполняемого потока. Иными словами, ни один поток не можёт~случайно 
повредить ее данные. А в Windows 95 последнее, увы, не реализовано, и есть 
вероятность, что выполняемый поток, случайно получив доступ к данным 
операционной системы, тем самым нарушит ее нормальную работу. И все-таки в 
Windows 95, как и в Windows NT, ни один поток не может получить доступ к 
памяти чужого процесса. Таким образом, хоть эта система и не застрахована от 
краха, она все же устойчивее к сбоям, чем 16-разрядная Windows. 

    81 

    82 ______________________________Windows для профессионалов 

    Итак, как я уже говорил, адресное пространство процесса закрыто. Отсюда 
вытекает, что процесс А в своем адресном пространстве может хранить какую-то 
структуру данных по адресу 0х12345678, и одновременно у процесса В по тому же 
адресу — но уже в его адресном пространстве — может находиться совершенно иная 
структура данных. Обращаясь к памяти по адресу 0х12345678, потоки, выполняемые 
в процессе А, получают доступ к структуре данных процесса А. Но, когда по тому 
же адресу обращаются потоки, выполняемые в процессе В, они получают доступ к 
структуре данных процесса В. Иначе говоря, потоки процесса А не могут 
обратиться к структуре данных в адресном пространстве процесса В, и наоборот. 
    А теперь, пока Вы не перевозбудились от колоссального объема адресного 
пространства, предоставляемого Вашей программе, вспомните, что оно 
виртуальное, а не физическое. Другими словами, адресное пространство — всего 
лишь диапазон адресов памяти. И, прежде чем Вы сможете обратиться к каким-либо 
данным, не вызвав нарушения доступа, придется отобразить нужную часть 
адресного пространства на конкретный участок физической памяти. (Об этом мы 
поговорим чуть позже.) 
    В разных реализациях Win32 разбиение 4-гигабайтового адресного 
пространства процесса на разделы осуществляется по-разному. Рассмотрим, как 
это делается в Windows 95 и Windows NT. 

    Как Windows 95 разбивает адресное пространство на разделы 

    На рис. 5-1 показано, как адресное пространство процесса разбивается на 
разделы под управлением Windows 95. 

    Раздел от 0х00000000 до 0х003 FFFFF 

    Этот регион размером 4 Мб в нижней части адресного пространства процесса 
необходим Windows 95 для поддержки совместимости с MS-DOS и 16-разрядной 
Windows. He пытайтесь обращаться к нему из Win32-приложений. В идеале 
процессор должен был бы генерировать нарушение доступа при обращении потока к 
этому участку памяти, но по техническим причинам Microsoft не смогла 
заблокировать эти 4 Мб адресного пространства. Доступ запрещен лишь к нижним 4 
Кб. И если поток Вашего процесса попытается прочесть или записать данные по 
одному из адресов в диапазоне от 0х00000000 до OxOOOOOFFF, процессор 
сгенерирует нарушение доступа. Защита этого четырехкилобайтового региона 
чрезвычайно полезна для выявления нулевых указателей. 
    Довольно часто в программах, написанных на С, отсутствует скрупулезная 
обработка ошибок. Например, в следующем фрагменте кода ее вообще нет: 

    int* pnSomeInteger; 
    pnSomeInteger = (int*)malloc(sizeof(int)); 
    «pnSomeInteger = 5: 

    При нехватке памяти malloc вернет NULL. .Но код не учитывает эту 
возможность и при ошибке обратится к памяти по адресу 0х00000000. А поскольку 
нижние 4 Кб адресного ~°- пространства заблокированы, возникнет нарушение 
доступа, и данный процесс завершится. Эта особенность помогает программистам 
находить «жучков» в своих приложениях. 

    Раздел от 0х00400000 до Ox/FFFFFFF 

    В этом разделе размером 2 143 289 344 байтов (2 Гб за вычетом 4 Мб) 
располагается закрытое (неразделяемое) адресное пространство процесса. Ни один 
Win32-npoiiecc не может получить 

    _______________________Глава 5. Архитектура памяти в Win32 83 

    OxFFFFFFFF     ^ 

    Регион размером 1 Гб для VxD-драйверов, диспетчера памяти и кода файловой 
системы; совместно используется всеми Win32-npoueccaMM (доступен для чтения и 
записи, но лучше туда ничего не записывать) 

    ОхСООООООО     ± 
    OxBFFFFFFF     ^ 

    Регион размером 1 Гб для проецируемых в память файлов, общих Win32 DLL, 
16-разрядных программ и выделяемых областей памяти; совместно используется 
всеми Win32-np04eccaMH (доступен для чтения и записи) 

    0х80000000     ± 
    Ox7FFFFFFF     Т 

    Регион размером 2 143 289 344 байтов, выделяемый в «личное» распоряжение 
\У!п32-процессам (незарезервирован, используется без ограничений) 

    0х00400000     ^ 
    OxOOSFFFFF     Т 

    Регион размером 4 1 90 208 байтов (доступен для чтения и записи, но лучше 
туда ничего не записывать) 

    0х00001000     ± 
    OxOOOOOFFF     T 

    Регион размером 4096 байтов для MS-DOS и 16-разрядной Windows (недоступен, 
позволяет выявлять нулевые указатели) 

    0х00000000     ± 

    Рис. 5-1. \Ут32-разделы в Windows 95 

    доступ к данным другого процесса, размещенным в этом разделе'. Основной 
объем данных, принадлежащих Wm32-npoueccy, хранится именно здесь. Поэтому 
УУш32-приложения менее зависимы от взаимных «капризов», да и вся система 
функционирует устойчивее. 

    Раздел от 0х80000000 до OxBFFFFFFF 

    В этом разделе размером 1 Гб система хранит данные, доступные всем 
\Ут32-процессам. Сюда загружаются, например, системнь1е_Е>ЬЬ: KERNEL32.DLL, 
USER32.DLL, GDI32.DLL и ADVAPI32.DLL. Соответственно эти DLL доступны всем 
выполняемым \Ут32-процессам, и для каждого процесса они загружаются по одному 
и тому же адресу. Кроме того, на этот раздел отображаются все проецируемые в 
память файлы (о них см. главу 8). 
    1. В Win32 все же предусмотрены две специальные функции (ReadProcessMemory 
и WriteProcessMemory), позволяющие одному процессу считывать или записывать 
данные в адресном пространстве другого процесса, но обычно их используют 
только отладчики. 

    84 ______________________________Windows для профессионалов 


    Раздел от ОхСООООООО до OxFFFFFFFF 

    В этом разделе размером 1 Гб находится код операционной системы, в том 
числе системные драйверы виртуальных устройств, код низкоуровневого управления 
памятью и файловой системой. Как и в предыдущем разделе, расположенный здесь 
код доступен всем Win32-npouecсам. К сожалению, этот раздел не защищен — любое 
\Ут32-приложение может считать или записать в него какие-нибудь данные, что в 
принципе грозит крахом операционной системы. 

    Как Windows NT разбивает адресное пространство на разделы 

    На рис. 5-2 показано, как адресное пространство процесса разбивается на 
разделы под управлением Windows NT. 

    OxFFFFFFFF     'k 
    Регион размером 2 Гб для операционной системы (недоступен) 
    0х80000000 
    Ox7FFFFFFF     Т 
    Регион размером 64 Кб для выявления указателей с неверными значениями (недоступен) 
    Ox7FFFOOOO     ^ 
    Ox7FFEFFFF     *k 
    Регион размером 2 147 352 576 байтов, выделяемый в «личное» распоряжение 
Win32-npoueccaM (незарезервирован, используется без ограничений) 
    0х00010000 
    OxOOOOFFFF 
    Регион размером 64 Кб для выявления нулевых указателей (недоступен) 
    0х00000000      ± 

    Рис. 5-2. Win32-pa3Qenbi в Windows NT 


    _____________________Глава 5. Архитектура памяти в Win32 85 


    Раздел от 0х00000000 до OxOOOOFFFF 

    Этот раздел (размером 64 Кб) в нижней части адресного пространства 
резервируется в Windows NT, чтобы программисты могли выявлять нулевые 
указатели — так же, как и в первых 4 Кб под управлением Windows 95. Любая 
попытка чтения или записи в память по этим адресам генерирует нарушение доступа. 

    Раздел от 0х00010000 до Ox7FFEFFFF 

    В этом разделе размером 2 147 352 576 байтов (2 Гб за вычетом 64 Кб и еще 
64 Кб) располагается закрытое адресное пространство процесса. Этот раздел 
аналогичен разделу от 0х00400000 до Ox7FFFFFFF B_Wmdows_95^                    
   "     ~"~ 
    При загрузке Win32-nponeccy необходим доступ к системным DLL: 
KERNEL32.DLL, USER32.DLL, GDI32.DLL и ADVAPI32.DLL. Код этих и других DLL 
помещается именно сюда. Каждый процесс может загрузить их по любому адресу в 
пределах данного раздела. Кроме того, система отображает на этот раздел все 
проецируемые в память файлы, доступные данному процессу. 

    Раздел от Ox7FFFOOOO до Ox7FFFFFFF 

    Этот раздел (размером 64 Кб) аналогичен разделу от 0х00000000 до 
OxOOOOFFFF, т. е. он тоже недоступен и любая попытка обращения к нему 
генерирует нарушение доступа. Microsoft резервирует этот раздел специально, 
чтобы упростить внутреннюю реализацию операционной системы. Вспомните: когда 
Вы передаете в Win32-cpyHKUHio адрес блока памяти и его размер, то она 
(функция), прежде чем приступить к работе, проверяет, действителен ли данный 
блок. Допустим, Вы написали код: 

    BYTE bBuf[70000]: 
    DWORD dwNumBytesWritten; 
    BOOL WriteProcessMemory(hProcess, Ox7FFEEE90, bBuf, sizeof(bBuf), &dwNumBytesWritten); 

    Так вот, в случае функций типа WriteProcessMemory область памяти, в 
которую предполагается запись, проверяется кодом, работающим в режиме ядра, — 
только он имеет право обращаться к памяти по адресам выше 0х80000000. Если по 
этому адресу есть память, вызов WriteProcessMemory, показанный выше, 
благополучно запишет данные в ту область памяти, которая по идее доступна 
только коду, работающему в режиме ядра. Чтобы предотвратить это и в то же 
время ускорить проверку таких областей памяти, Microsoft предпочла 
заблокировать раздел от Ox7FFFOOOO до Ox7FFFFFFF, и поэтому любая попытка 
чтения или записи в данной области памяти всегда генерирует нарушение доступа. 

    Раздел от 0х80000000 до OxFFFFFFFF 

    В этот раздел (размером 2 Гб) загружаются Windows NT Executive, ядро и 
драйверы устройств. В отличие от Windows 95 компоненты операционной системы 
Windows NT полностью защищены. При попытке обратиться по одному из этих 
адресов Ваш поток вызовет нарушение доступа, что приведет к появлению на 
экране соответствующего сообщения и к завершению всей программы. Подробнее о 
нарушении доступа и принципах его обработки см. главу 16. 
    Вероятно, Вы сейчас подумали, что со стороны Windows NT весьма неразумно 
отбирать у приложения целых 2 Гб адресного пространства, и я вынужден с Вами 
согласиться. Однако это сделано из-за процессора MIPS R4000, которому 
необходим данный диапазон адресов. Конечно, Microsoft могла бы реализовать 
Win32 для Windows NT на разных платформах по-разному, но решила (и, по-моему, 
вполне оправданно) упростить перенос приложений с платформы на платформу, 
зарезервировав эти 2 Гб во всех реализациях Win32 для Windows NT. 

    86 ______________________________Windows для профессионалов 


    Регионы в адресном пространстве 

    Адресное пространство, выделяемое процессу в момент создания, практически 
все свободно (незарезервировано). Поэтому, чтобы воспользоваться какой-нибудь 
его частью, нужно выделить в нем определенные регионы, вызвав \Уш32-функцию 
VirtualAlloc (о ней см. главу 7). Операция выделения региона называется 
резервированием (reserving). 
    При резервировании система обязательно выравнивает начало региона по 
четному адресу и учитывает так называемую гранулярность выделения ресурсов 
(allocation granularity). Последняя величина в принципе зависит от типа 
процессора, но у рассматриваемых в книге (х86, MIPS, Alpha и PowerPC) она 
одинакова и составляет 64 Кб. Понятие «гранулярность выделения ресурсов» 
применяется в системе, чтобы упростить служебную запись, хранящую информацию о 
регионах, зарезервированных в адресном пространстве Вашего процесса, а также 
чтобы снизить степень фрагментации регионов в этом пространстве. 
    Резервируя регион в адресном пространстве, система обеспечивает еще и 
четную кратность размера региона размеру страницы. Так называется единица 
объема памяти, используемая системой при управлении памятью. Как и 
гранулярность выделения ресурсов, размер страницы зависит от типа процессора. 
В частности, в реализации Win32 для процессоров х86, MIPS и PowerPC он равен 4 
Кб, а для DEC Alpha — 8 Кб. 
    Если Вы попытаетесь зарезервировать регион в 10 Кб, система автоматически 
округлит заданное Вами значение до большей четной кратной величины. А это 
значит, что на процессорах xS6, MIPS и PowerPC будет выделен регион размером 
12 Кб, а на процессоре Alpha — 16 Кб. 
    И последнее в этой связи. Когда зарезервированный регион адресного 
пространства становится не нужен, его следует вернуть в общие ресурсы системы. 
Эта операция — освобождение (releasing) региона — осуществляется вызовом 
функции VirtualFree. 

   /ВНИМАНИЕ\ 
    Иногда система сама резервирует некоторые регионы адресного 
пространства «в интересах» Вашего процесса, например, для хранения блока 
переменных окружения процесса (process environment block, РЕВ). Это 
блок — небольшая структура данных, создаваемая, управляемая и разрушаемая 
исключительно операционной системой. Выделение региона под РЕВ-блок 
осуществляется в момент создания процесса. 

    Кроме того, для управления потоками, существующими на данный момент в 
процессе, система создает блоки переменных окружения потоков (thread 
environment blocks, TEBs). Регионы под эти блоки резервируются и освобождаются 
по мере создания и разрушения потоков в процессе. 
    Отметим также: требуя от Вас резервировать регионы с учетом гранулярности 
выделения ресурсов, сама система этих правил не придерживается. Поэтому вполне 
вероятно, что границы региона, зарезервированного под РЕВ- и ТЕВ-блоки, не 
будут кратны 64 Кб. Тем не менее размер такого региона обязательно кратен 
размеру страниц, характерному для данного типа процессора. 

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

    Чтобы практически использовать зарезервированный регион адресного 
пространства, нужно выделить физическую память и отобразить ее на этот регион. 
Такая операция называется передачей физической памяти (committing physical 
storage). Чтобы передать физическую память зарезервированному региону, Вы 
обращаетесь все к той же функции VirtualAlloc. Передавая физическую память 
регионам, нет нужды отводить ее целому региону. Можно, скажем, зарезервировать 
регион размером 64 Кб и передать физическую память 

    ______________________Глава 5. Архитектура памяти в Win32 87 

    только его второй и четвертой страницам. На рис. 5-3 представлен пример 
того, как может выглядеть адресное пространство процесса. Заметьте: структура 
адресного пространства зависит от архитектуры процессора. Так, на рис. 5-3 
слева показано, что происходит с адресным пространством на процессорах xS6, 
MIPS и PowerPC (страницы по 4 Кб), а справа — на процессоре DEC Alpha 
(страницы по 8 Кб). 
    Когда физическая память, переданная зарезервированному региону, больше не 
нужна, ее освобождают. Эта операция — возврат физической памяти (decommitting 
physical storage) — выполняется вызовом функции VirtualFree. 

    х86, MIPS и PowerPC      DEC Alpha 
    
    Страницы 11-16       Страницы 6-8 
    (24 576 байтов)        (24 576 байтов) 
    Страница 10 
    '4()96байтов'          Страница 5 
    Страница 9             (8192 байта) 
    (4096 байтов) 
    Страница 8 
    (4096 байтов)          Страница 4      64-килобайтовый регион 
    ~~~У1        (8192 байта)    в адресном пространстве 
    страница / я"        •         ' 
    (4096 байтов) 
    Страница 6 
    (4096 байтов)          -       
    ___________        Страница 3 
    Страница 5 •""""         (8192 байта) 
    (4096 байтов) 
    Страница 4 
    (Мбайтов)          Страница 2 
    Страница 3             (8192 байта) 
    (4096 байтов) 
    Страница 2 
    (4096 байтов)          -,       , 
    Страница 1 
    Страница!(8192 байта) 
    (4096 байтов) ,                         v 
    I               ff _1_ 

    Рис. 5-3. Примеры адресных пространств процессов для разных типов процессоров 


    Физическая память 

    В 16-разрядной Windows физической памятью считается вся оперативная память 
(random access memory, RAM), установленная в компьютере. Иначе говоря, если в 
Вашей машине 16 Мб оперативной памяти. Вы можете загружать и выполнять 
приложения, использующие вплоть до 16 Мб памяти. Для более экономного 
расходования памяти в 16-разрядной Windows 

    88 ______________________________Windows для профессионалов 

    предусмотрено множество всяких механизмов оптимизации. Например> если Вы 
запускаете две (или более) копии одного приложения, для каждой копии создается 
новый сегмент данных, но программный код приложения не дублируется — все копии 
работают на одном эк^ земпляре программного кода. Благодаря этому удается 
значительно уменьшить потребности в памяти при одновременном выполнении 
нескольких копий одного приложения. 
    Кроме того, 16-разрядная Windows поддерживает виртуальную память, 
реализуемую в виде файлов подкачки (swap files), размещаемых на жестком диске. 
Однако операционная система способна использовать файлы подкачки, только если 
работу с ними поддерживает сам процессор. Именно поэтому 16-разрядная Windows 
задействует файлы подкачки лишь при выполнении на компьютерах с процессором 
386 и старше. Файл подкачки позволяет увеличить объем памяти, доступный 
приложению. Если в Вашей машине 16 Мб оперативной памяти, а на жестком диске — 
файл подкачки размером 20 Мб, приложение «считает», что его запускают на 
компьютере с 36 Мб оперативной памяти. 
    Конечно, 36 Мб оперативной памяти у Вас на самом деле нет. Операционная 
система в тесной координации с процессором просто сбрасывает содержимое части 
оперативной памяти в файл подкачки и по мере необходимости подгружает его 
порции обратно в память. Поскольку файл подкачки явным образом увеличивает 
объем памяти, доступный приложениям, его применение в 16-разрядной Windows 
весьма желательно. А если такого файла нет, система просто считает, что 
приложениям доступен меньший объем памяти, — вот и все. 
    В Windows 95 и Windows NT управление памятью принципиально отличается от 
принятого в Windows 3.1. В них вся оперативная память обслуживается 
исключительно системой, и ни одно приложение не может напрямую контролировать 
эту память. 
    Так что в Win32-CHcreMax физическую память следует рассматривать как 
данные, хранимые в дисковых файлах со страничной структурой — страничных 
файлах (paging files). Поэтому, когда приложение передает физическую память 
какому-нибудь региону адресного пространства (вызывая VirtualAlloc), она на 
самом деле выделяется из файла, размещенного на жестком диске. Размер 
страничного файла в системе — главный фактор, определяющий количество 
физической памяти, доступное приложениям. Реальный объем оперативной памяти 
имеет гораздо меньшее значение. 
    Теперь посмотрим, что происходит, когда поток пытается получить доступ к 
блоку данных в адресном пространстве своего процесса. Произойти может одно из 
двух (см. рис. 5-4). В первом сценарии данные, к которым обращается поток, 
находятся в оперативной памяти. В этом случае процессор отображает виртуальный 
адрес данных на физический, и поток получает доступ к нужным ему данным. 
    Во втором сценарии данные, к которым обращается поток, отсутствуют в 
оперативной памяти, но размещены где-то в страничном файле. Попытка доступа к 
данным генерирует ошибку страницы (page fault), и процессор таким образом 
уведомляет операционную систему об этой попытке. Тогда операционная система 
начинает искать свободную страницу в оперативной памяти; если таковой нет, 
система вынуждена освободить одну из занятых страниц. Если занятая страница не 
модифицировалась, она просто освобождается; в ином случае она сначала 
копируется из оперативной памяти в страничный файл. После этого система 
переходит к страничному файлу, отыскивает в нем запрошенный блок данных, 
загружает этот блок на свободную страницу оперативной памяти и, наконец, 
отображает адрес данных в виртуальной памяти на соответствующий адрес в 
физической памяти. 
    Сами понимаете: чем чаще системе приходится копировать страницы памяти в 
страничный файл и наоборот, тем больше нагрузка на жесткий диск и тем 
медленнее работает операционная система. (При этом, кстати, может получиться 
так, что операционная система будет тратить все свое время на подкачку страниц 
вместо выполнения программ.) Так что, добавив компьютеру оперативной памяти, 
Вы снизите частоту обращения к жесткому диску и тем самым увеличите общую 
производительность системы. 

    _______________________Глава 5. Архитектура памяти в Win32 89 


    Поток обращается   j к блоку данных^^ 
    Данные                           Генерируется \ 
    Данные            —гт     „                                           r r' 
     \ 
    в RAMS   У———————>-  в страничном „———НЕТ—————>-    нарушение    1 
    х       '^<   (генерируется     \&оЛмЯ^Г                          доступа  
 ^ 
    \ ^г     ошибка страницы)      \^ ^'                         "^          '' 
    ДА 
    \ 
    ДА                       ,К, 
    tcTb ли                        Система ищет в RAM, 
    в RAM свободная,———— НЕТ ————>-   какую страницу 
    Хстраница^»»-                      можно освободить 
    ДА                        V 
    v                                                 ^ 
    Процессор                     Данные загружаютсй5                       " 
    отображает     ^__________  из страничного   -<—— НЕТ ————. Модифицирована 
    виртуальный адрес                   файла на свободную   _____       -^ли 
эта страница^»
    на физический                       страницу RAM   "^|             '\ ^^^ 
    ДА 
    + 
    v                                                          Содержимое 
    Поток получает \                                              _____     страницы 
    доступ к данным^                                                          сбрасывается 
    '"           "^                                                         в 
страничный файл 
    
    Рис. 5-4. Вот так осуществляется доступ к данным 


    VwiNDowsy NT 

    Windows NT может использовать несколько страничных файлов, и, если они • 
расположены на разных физических дисках, операционная система работает гораздо 
быстрее, поскольку способна вести запись одновременно на нескольких дисках. 
Чтобы добавить или удалить страничный файл, откройте Control Panel, дважды 
щелкните значок System, выберите вкладку Performance и в разделе Virtual 
Memory щел кните кнопку Change. 

    Физическая память в страничном файле не хранится 

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

    90 ______________________________Windows для профессионалов 

    копирует код и данные из файла программы (расположенного на жестком диске) 
в физическую память, переданную из страничного файла. 
    Однако система действует не так, иначе на загрузку и подготовку программы 
к запуску уходило бы слишком много времени. На самом деле происходит вот что: 
при запуске приложения система открывает его исполняемый файл и определяет 
объем кода и данных приложения. Затем резервирует регион адресного 
пространства и помечает, что физическая память, связанная с этим регионом, — 
сам ЕХЕ-файл. Да-да, правильно: вместо выделения какого-то пространства из 
страничного файла система использует истинное содержимое, или образ (image) 
ЕХЕ-файла как зарезервированный регион адресного пространства программы. 
Благодаря этому приложение загружается очень быстро, а размер страничного 
файла удается заметно уменьшить. 
    Образ исполняемого файла (т. е. ЕХЕ- или DLL-файл), размещенный на жестком 
диске и применяемый как физическая память для того или иного региона адресного 
пространства, называется проецируемым в память файлом (memory-mapped file). 
При загрузке ЕХЕ или DLL система автоматически резервирует регион адресного 
пространства и проецирует на него образ файла. Помимо этого, система позволяет 
(с помощью группы \Ут32-функций) проецировать на регион адресного пространства 
еще и файлы данных. (О проецируемых в память файлах мы поговорим в главе 8.) 

    /ВНИМАНИЕ^ 
    Когда ЕХЕ- или DLL-файл загружается с дискеты, Windows 95 и Windows NT 
выделяют для него всю память из страничного файла. Далее система копирует файл 
с дискеты в оперативную память и в страничный файл; в этом случае страничный 
файл служит фактически копией содержимого оперативной памяти. Так, в 
частности, загружаются программы, устанавливающие приложения на компьютер. 

    Обычно программа установки запускается с первой дискеты, потом поочередно 
вставляются следующие диски, на которых собственно и содержится 
устанавливаемое приложение. Если системе понадобится какой-то фрагмент кода 
ЕХЕ- или DLL-модуля программы установки, на текущей дискете его, конечно же, 
нет. Но, поскольку система скопировала файл в оперативную память и в 
страничный файл, у нее не возникнет проблем с доступом к нужному коду 
программы установки. Ну а по окончании ее работы система освободит оперативную 
память и память, выделенную в страничном файле. 
    Система не копирует в оперативную память образы файлов, хранящихся на 
других съемных носителях (CD-ROM или сетевых дисках), если только требуемый 
файл не скомпонован с использованием ключа /SWAPRUN:CD или /SWAPRUN:NET. 

    Атрибуты защиты 

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

    Атрибут защиты               Описание 

    PAGE_NOACCESS              Попытки чтения, записи или исполнения 
содержимого памяти в этом регионе вызывают нарушение доступа. 
    PAGE_READONLY             Попытки записи или исполнения содержимого памяти 
в этом регионе вызывают нарушение доступа. 
    PAGE_READWRITE            Попытки исполнения содержимого памяти в этом 
регионе вызывают нарушение доступа. 
    см. след. стр. 

    _____________________Глава 5. Архитектура памяти в Win32 91 

    продолжение 

    Атрибут защиты               Описание 

    PAGE_EXECUTE               Попытки чтения или записи в этом регионе вызывают 
    нарушение доступа. 
    PAGE_EXECUTE_READ         Попытки записи в этот регион вызывают нарушение доступа. 
    PAGE_EXECUTE_READWRITE   Данный регион допускает любые операции. 
    PAGE_WRITECOPY             Попытки исполнения содержимого памяти в этом регионе 
    вызывают нарушение доступа. Запись в него приводит к тому, что процессу 
предоставляется «личная» копия данной страницы физической памяти. 
    PAGE_EXECUTE_WRITECOPY    Данный регион допускает любые операции. Запись в него 
    приводит к тому, что процессу предоставляется «личная» копия данной 
страницы физической памяти. 
    На^цтатфо^шах х86, MIPS, PowerPC и Alpha атрибут PAGE_EXECUTE не 
поддержива-, ^ется, хотя в операционных системах на базе Win32 такая поддержка 
предусмотрена. Перечисленные процессоры воспринимают запрос на чтение как 
запрос на исполнение. Поэтому присвоение памяти атрибута PAGE_EXECUTE приводит 
к тому, что на этих процессорах она считается доступной и для чтения. Но 
полагаться на эту особенность не стоит, поскольку в реализациях Windows NT на 
других процессорах все может встать на свои места. 

    VWINDOWS/ 
    В Windows 95 страницам физической памяти можно присвоить только 3 атрибута 
защиты: PAGE_NOACCESS, PAGE_READONLY и PAGE_READWRITE. 


    Защита типа «копирование при записи» 

    Атрибуты защиты, перечисленные в предыдущей таблице, достаточно понятны, 
кроме двух последних: PAGE_WRITECOPY и PAGE_EXECUTE_WRITECOPY. Они 
предназначены специально для экономного расходования оперативной памяти и 
места в страничном файле. Win32 поддерживает механизм, позволяющий двум и 
более процессам разделять один и тот же блок данных. И обычно никаких проблем 
не возникает — пока процессы в него ничего не записывают. Представляете, что 
творилось бы в системе, если б потоки из разных процессов начали одновременно 
записывать в один и тот же блок данных! 
    Чтобы предотвратить этот хаос, операционная система присваивает общему 
блоку данных атрибут защиты «копирование при записи» (copy-on-write). Когда 
поток в одном процессе попытается что-нибудь записать в общий блок данных, в 
дело тут же вступит система и: 
    1. Выделит из страничного файла страницу физической памяти. 
    2. Найдет свободную страницу оперативной памяти. 
    3. Скопирует страницу с данными, которые поток пытается записать в общий 
блок данных, на свободную страницу оперативной памяти, полученную на этапе 2. 
    4. Отобразит виртуальный адрес этой страницы в процессе на новую страницу 
оперативной памяти. 
    Когда система выполнит эти операции, процесс получит свою копию нужной 
страницы данных. Подробнее о совместном использовании памяти и о защите типа 
«копирование при записи» я расскажу в главе 8. 

    92 ______________________________Windows для профессионалов 

    Кроме того, при резервировании адресного пространства или передаче 
физической памяти через VirtualAlloc нельзя указывать атрибуты PAGE_WRITECOPY 
или PAGE_EXECUTE_WRITECOPY. Иначе вызов VirtualAlloc даст ошибку, a 
GetLastError вернет код ERROR_INVALID_PARAMETER. Дело в том, что эти два 
атрибута используются операционной системой, только когда она проецирует 
образы ЕХЕ- или DLL-файлов. 

    XWINDOWS/ 
    Windows 95 не поддерживает защиту типа «копирование при записи». Обнаружив 
запрос на применение такой защиты. Windows 95 тут же делает копии данных, не 
дожидаясь попытки записи в.память. 


    Специальные флаги атрибутов защиты 

    Кроме рассмотренных атрибутов защиты, существуют два флага атрибутов 
защиты: РАGE_NOCACHE и PAGE_GUARD. Они комбинируются с любыми атрибутами 
защиты (кроме PAGE_NOACCESS) побитовой операцией OR. 
    Флаг PAGE_NOCACHE отключает кэширование переданных страниц. Как правило, 
этот флаг использовать не рекомендуется; он предусмотрен главным образом для 
разработ чиков драйверов устройств, которым нужно манипулировать буферами памяти. 
    Флаг PAGE_GUARD в обычных ситуациях также не рекомендуется. Windows NT 
использует его при создании стека потока. Подробнее об этом флаге см. раздел 
«Стек пото ка» в главе 7. 
    
    XWINDOWS/ 
    Windows 95 игнорирует флаги атрибутов защиты PAGE_NOCACHE и РАGE_GUARD. 


    Подводя итоги 

    А теперь попробуем осмыслить понятия адресных пространств, разделов, 
регионов, блоков и страниц как единое целое. Лучше всего начать с изучения 
карты виртуальной памяти, на которой изображены все регионы адресного 
пространства в пределах одного процесса. В качестве примера возьмем программу 
VMMAP.EXE из главы 6. Чтобы в полной мере разобраться в адресном пространстве 
процесса, рассмотрим его в том виде, в каком оно формируется при запуске 
приложения VMMap под управлением Windows NT. Образец карты его адресного 
пространства показан в таблице на рис. 5-5. На отличиях адресных пространств в 
Windows NT и Windows 95 я остановлюсь чуть позже. 

    Базовый                                 Атрибут(ы) 
    адрес      Тип        Размер   Блоки   защиты        Описание 
    00000000     Free           65536 
    00010000     Private         4096    1        -RW
    00011000     Free           61440 
    00020000     Private         4096    1        -RW
    00021000     Free           61440 
    00030000     Private      1048576    3        -RW-    стек потока 
    00130000     Private         4096    1        -RW
    00131000     Free           61440 
    00140000     Private      1048576    2        -RW-    стандартная куча процесса 
    см. след. cmf 

    Рис. 5-5. Образец карты адресного пространства процесса в Windows NT 


    ______________________Глава 5. Архитектура памяти в Win32 93 


    РИС. 5-5 (продолжение) 

    Базовый Атрибут(ы) 

    адрес Тип Размер Блоки защиты Описание 

    00240000 Mapped 65536 2 -RW
    00250000 Mapped 36864 1 -R-
    00259000 Free 28672 
    00260000 Mapped 139264 1 -R-
    00282000 Free 57344 
    00290000 Mapped 266240 1 -R-
    002D1000 Free 61440 
    002ЕОООО Mapped 12288 1 -R-
    002ЕЗООО Free 53248 
    002FOOOO Mapped 819200 4 ER-
    ООЗВ8000 Free 32768 
    ООЗСОООО Mapped 143360 1 -R-
    ООЗЕЗООО Free 118784 
    00400000 Image 36864 5 ERWC C:\AdvWin\virimap. 06\dbg_x86\vmmap. exe 
    00409000 Free 28672 
    00410000 Mapped 3145728 2 ER-
    00710000 Private 4096 1 -RW
    00711000 Free 61440 
    00720000 Private 4096 1 -RW
    00721000 Free 61440 
    00730000 Private 4096 1 -RW
    00731000 Free 61440 
    00740000 Private 131072 2 -RW
    00760000 Private 65536 2 -RW
    00770000 Free 1999110144 
    779FOOOO Image 98304 5 ERWC D:\WINNT\system32\msvcrt40.dll 
    77А08000 Free 32768 
    77А10000 Image 253952 5 ERWC D:\WINNT\systeiTi32\msvcrt40. dll 
    77А4ЕООО Free 3612672 
    77DCOOOO Image 249856 6 ERWC 0:\WINNT\system32\advapi32.dll 
    770FDOOO Free 143360 
    77E20000 Image 299008 5 ERWC D:\WINNT\system32\rpcrt4.dll 
    77E69000 Free 28672 
    77E70000 Image 335872 5 ERWC D:\WINNT\system32\user32.dll 
    77EC2000 Free 57344 
    77EDOOOO Image 176128 5 ERWC D:\WINNT\system32\gdi32.dll 
    77EFBOOO Free 20480 
    77FOOOOO Image 372736 5 ERWC D:\WINNT\system32\kernel32.dll 
    77F5BOOO Free 20480 
    77F60000 Image 372736 8 ERWC 0:\WINNT\system32\ntdll.dll 
    77FBBOOO Free 123949056 
    7F5FOOOO Mapped 2097152 3 ER-
    7F7FOOOO Free 8126464 
    7FFBOOOO Mapped 147456 1 -R-
    7FFD4000 Free 40960 
    7FFDEOOO Private 4096 1 ERW
    7FFDFOOO Private 4096 1 ERW
    7FFEOOOO Private 65536 2 -R-


    94 ______________________________Windows для профессионалов 

    Карта на рис. 5-5 показывает регионы, расположенные в адресном 
пространстве процесса. Каждому региону соответствует своя строка в таблице, а 
каждая строка состоит из шести полей. 
    В первом (крайнем слева) поле проставляется базовый адрес региона. 
Наверное, Вы заметили, что просмотр адресного пространства мы начали с региона 
по адресу 0х00000000 и закончили последним регионом используемого адресного 
пространства, который начинается по адресу Ox7FFEOOOO. Все регионы непрерывны. 
Почти все базовые адреса занятых регионов начинаются с четных значений, 
кратных 64 Кб. Это связано с гранулярностью выделения регионов в адресном 
пространстве. А если Вы увидите какой-нибудь регион, начало которого не 
выровнено по значению, кратному 64 Кб, значит, он выделен кодом операционной 
системы для управления Вашим процессом. 
    Во втором поле показывается тип региона: free (свободный), private 
(закрытый), image (образ) или mapped (проецируемый). Эти типы описаны в таблице: 

    Тип      Описание 

    Free     Незарезервированный регион адресного пространства; приложение может 
    зарезервировать регион по указанному базовому адресу или в любом месте в 
границах свободного региона. 
    Private   Регион содержит физическую память из страничного файла. 
    Image    Регион содержит физическую память из проецируемого в память ЕХЕ- 
или DLL-файла. 
    Mapped Регион содержит физическую память из проецируемого в память файла данных. 

    Способ вычисления этого поля моей программой VMMap может давать 
неправильные результаты. И вот почему. Когда регион занят, VMMAP.ЕХЕ пытается 
«прикинуть», к какому из трех оставшихся типов он может относиться, — в Win32, 
к сожалению, нет функций, способных подсказать точное предназначение региона. 
Я определяю это сканированием всех блоков в границах исследуемого региона, по 
результатам которого программа делает обоснованное предположение. Но 
предположение есть предположение. Впрочем, если хотите получше разобраться в 
том, как это делается, просмотрите код VMMAP.EXE, приведенный в главе 6. 
    В третьем поле сообщается размер региона в байтах. Например, система 
спроецировала образ USER32.DLL по адресу Ох77Е70000. Когда она резервировала 
адресное пространство для этого образа, ей понадобилось 335 872 байта. Не 
забудьте, что в третьем поле всегда содержатся четные значения, кратные 
размеру страницы, характерному для данного процессора (4096 байтов для х86). 
    В четвертом поле показано количество блоков в зарезервированном регионе. 
Блок — это неразрывная группа страниц с одинаковыми атрибутами защиты, 
связанная с одним и тем же типом физической памяти (подробнее об этом мы 
поговорим в следующем разделе). Для свободных регионов это значение всегда 
равно 0, так как им не передается физическая память. (Поэтому в четвертой 
графе никаких данных для свободных регионов не приводится.) Но для занятых 
регионов это значение может колебаться в пределах от 1 до максимума (его 
вычисляют делением размера региона на размер страницы). Скажем, у региона, 
начинающегося с адреса Ох77Е70000, размер — 335 872 байта. Поскольку процесс 
выполняется на процессоре xS6 (страницы памяти по 4096 байтов), максимальное 
количество блоков в этом регионе равно 82 (335 872/4096); ну а, судя по карте, 
в нем содержится 5 блоков. 
    В пятом поле — атрибуты защиты региона. Здесь используются следующие 
сокращения: Е = execute (исполнение), R = read (чтение), W = write (запись), С 
= copy-on-write (копирование при записи). Если ни один из атрибутов в этой 
графе не указан, регион доступен без ограничений. Атрибуты защиты не 
присваиваются и свободным регионам. Кроме того, здесь 

    _____________________Глава 5. Архитектура памяти в Win32 95 

    Вы никогда не увидите флагов атрибутов защиты (PAGE_GUARD или 
PAGE_NOCACHE) — они имеют смысл только для физической памяти, а не для 
зарезервированного адресного пространства. Атрибуты защиты присваиваются 
регионам только эффективности ради и всегда замещаются атрибутами защиты, 
присвоенными физической памяти. 
    В шестом (и последнем) поле кратко описывается содержимое текущего 
региона. Для свободных регионов оно всегда пустое, а для закрытых — обычно 
пустое, так как у VMMAP.EXE нет возможностей выяснить, зачем приложение 
зарезервировало данный закрытый регион. Однако два типа закрытых регионов 
VMMAP.EXE все же распознает: стеки потоков и стандартную кучу процесса 
(default process heap). Стеки потоков «выдают» себя тем, что содержат блок 
физической памяти с флагом атрибутов защиты PAGE_GUARD. Если же стек полностью 
заполнен, такого блока у него нет, и тогда VMMAP.EXE не распознает стек 
потока. Ну а стандартную кучу процесса (о ней см. главу 9) VMMAP.EXE 
обнаруживает очень просто: получив базовый адрес региона, сравнивает его со 
значением, возвращенным функцией GetProcessHeap. 
    Для регионов типа image программе VMMAP.EXE удается определить полное имя 
файла, проецируемого на этот регион. (Она получает эту информацию вызовом 
GetModuleFileName.) Но вот по регионам типа mapped в шестой графе ничего не 
сообщается, так как у программы нет возможности определить, какой файл данных 
проецируется на тот или иной регион. 

    Блоки внутри регионов 

    Попробуем увеличить детализацию адресного пространства (по сравнению с 
тем, что показано на рис. 5-5). Например, таблица на рис. 5-6 показывает ту же 
карту адресного пространства, но в другом «масштабе»: по ней можно узнать, из 
каких блоков состоит каждый регион. 

    Базовый  адрес    Атрибут(ы)  Тип        Размер   Блоки   защиты        Описание 

    00000000     Free           65536 
    00010000     Private         4096    1        -RW
    00010000 Private         4096    1        -RW
    00011000     Free           61440 
    00020000     Private         4096    1        -RW
    00020000 Private        4096    1        -RW
    00021000     Free           61440 
    00030000     Private      1048576    3        -RW-   стек потока 
    00030000 Reserve      1036288             -RW
    0012DOOO Private        4096             -RW-   G
    0012ЕООО Private         8192             -RW
    00130000     Private         4096    1        -RW
    00130000 Private         4096    1        -RW
    00131000     Free           61440 
    00140000     Private      1048576    2        -RW-   стандартная куча процесса 
    00140000 Private        12288             -RW
    00143000 Reserve      1036288             -RW
    00240000     Mapped         65536    2        -RW
    00240000 Mapped          4096             -RW
    00241000 Reserve        61440             -RW
    см. след. стр. 

    Рис. 5-6. Образец карты адресного пространства процесса (с указанием 
блоков внутри регионов) в Windows NT 

    96 _____________________________Windows для профессионалов 

    РИС. 5-6 (продолжение) 

    Базовый адрес Атрибут(ы) Тип Размер Блоки защиты Описание 

    00250000 Mapped 36864 1 -R-
    00250000 Mapped 36864 -R-- -
    00259000 Free 28672 
    00260000 Mapped 139264 1 -R— 
    00260000 Mapped 139264 -R-- -
    00282000 Free 57344 
    00290000 Mapped 266240 1 -R
    00290000 Mapped 266240 -R— -
    002D1000 Free 61440 
    002ЕОООО Mapped 12288 1 -R-
    002ЕОООО Mapped 12288 -R-- -
    002ЕЗООО Free 53248 
    002FOOOO Mapped 819200 4 ER-
    002FOOOO Mapped 12288 ER-- -
    002F3000 Reserve 774144 ER-- -
    ООЗВОООО Mapped 4096 ER-- -
    ООЗВ10000 Reserve 28672 ER-- -
    ООЗВ8000 Free 32768 
    ООЗСОООО Mapped 143360 1 -R-
    ООЗСОООО Mapped 143360 -R— -
    ООЗЕЗООО Free 118784 
    00400000 Image 36864 5 ERWC C:\AdvWin\vmmap.06\dbg_x86\vmmap.exe 
    00400000 Image 4096 -R-- -
    00401000 Image 12288 ER-- -
    00404000 Image 4096 -R-- -
    00405000 Image 8192 -RW- -
    00407000 Image 8192 -R-- -
    00409000 Free 28672 
    00410000 Mapped 3145728 2 . ER-
    00410000 Mapped 512000 ER-- -
    00480000 Reserve 2633728 ER— -
    00710000 Private 4096 1 -RW
    00710000 Private 4096 -RW- -
    00711000 Free 61440 
    00720000 Private 4096 1 -RW
    00720000 Private 4096 -RW- -
    00721000 Free 61440 
    00730000 Private 4096 1 -RW
    00730000 Private 4096 -RW- -
    00731000 Free 61440 
    00740000 Private 131072 2 -RW
    00740000 Private 4096 -RW- -
    00741000 Reserve 126976 -RW- -
    00760000 Private 65536 2 -RW
    00760000 Private 8192 -RW- -
    00762000 Reserve 57344 -RW- -
    00770000 Free 1999110144 -RW- -
    см. след. стр. 


    ______________________Глава 5. Архитектура памяти в Win32 97 


    РИС. 5-6 (продолжение) 


    Базовый Атрибут(ы) 

    адрес Тип Размер Блоки защиты Описание 

    779FOOOO Image 98304 5 ERWC D:\WINNT\system32\insvcrt40. dll 
    779FOOOO Image 4096 -R" -
    779F1000 Image 32768 ER-- -
    779F9000 Image 49152 -R-- -
    77A05000 Image 4096 -RW- -
    77A06000 Image 8192 -R-- -
    77A08000 Free 32768 
    77A10000 Image 253952 5 ERWC D:\WINNT\system32\msvcrt.dll 
    77A10000 Image 4096 -R-- -
    77A11000 Image 184320 ER" -
    77A3EOOO Image 28672 -R" -
    77A45000 Image 20480 -RW- -
    77A4AOOO Image 16384 -R-- -
    77A4EOOO Free 3612672 
    77DCOOOO Image 249856 6 ERWC D:\WINNT\system32\advapi32. dll 
    77DCOOOO Image 4096 -R-- -
    77DC1000 Image 172032 ER-- — 
    77DEBOOO Image 36864 -R— -
    77DF4000 Image 16384 -RWC -
    77DF8000 Image 4096 -RW- -
    77DF9000 Image 16384 -R— -
    77DFDOOO Free 143360 
    77E20000 Image 299008 5 ERWC D:\WINNT\system32\rpcrt4.dll 
    77E20000 Image 4096 -R-- -
    77E21000 Image 241664 ER-- -
    77E5COOO Image 16384 -R-- -
    77E60000 Image 4096 -RW- -
    77E61000 Image 32768 -R-- -
    77E69000 Free 28672 
    77E70000 Image 335872 5 ERWC D:\WINNT\system32\user32.dll 
    77E70000 Image 4096 -R-- -
    77E71000 Image 258048 ER-- -
    77EBOOOO Image 32768 -R-- -
    77EB8000 Image 4096 -RW- -
    77EB9000 Image 36864 -R-- -
    77EC2000 Free 57344 
    77EDOOOO Image 176128 5 ERWC D:\WINNT\system32\gdi32.dll 
    77EDOOOO Image 4096 -R-- -
    77ED1000 Image 143360 ER-- -
    77EF4000 Image 4096 -R-- -
    77EF5000 Image 4096 -RW- -
    77EF6000 Image 20480 -R-- -
    77EFBOOO Free 20480 
    77FOOOOO Image 372736 5 ERWC D:\WINNT\system32\kernel32.dll 
    77FOOOOO Image 4096 -R-- -
    77F01000 Image 237568 ER-- -
    77F3BOOO Image 36864 -R-- -
    см. след. стр. 


    98 _____________________________Windows для профессионалов 


    РИС. 5-6 (продолжение) 

    Базовый адрес   Атрибут(ы)  Тип        Размер   Блоки   защиты        Описание 

    77F44000 Image          8192             -RW- -
    77F46000 Image          86016             -R-- -
    77F5BOOO     Free           20480 
    77F60000     Image         372736    8        ERWC   D:\WINNT\system32\ntdll.dll 
    77F60000 Image          4096             -R" -
    77F61000 Image         233472             ER-- -
    77F9AOOO Image          32768             -R-- -
    77FA2000 Image           4096             -RW- -
    77FA3000 Image           4096             -RWC -
    77FA4000 Image           8192             -RW- -
    77FA6000 Image           4096             -RWC -
    77FA7000 Image          81920             -R-- -
    77FBBOOO     Free       123949056 
    7F5FOOOO     Mapped       2097152    3        ER-
    7F5FOOOO Reserve      1048576             ER-- -
    7F6FOOOO Mapped         28672             ER-- -
    7F5F7000 Reserve      1019904             ER-- -
    7F7FOOOO     Free         8126464 
    7FFBOOOO     Mapped        147456    1        -R-
    7FFBOOOO Mapped        147456             -R-- -
    7FFD4000     Free           40960 
    7FFDEOOO     Private         4096    1        ERW
    7FFDEOOO Private         4096             ERW- -
    7FFOFOOO     Private         4096    1        ERW
    7FFOFOOO Private        4096             ERW- -
    7FFEOOOO     Private        65536    2        -R-
    7FFEOOOO Private         4096             -R" -
    7FFE1000 Reserve       61440             -R-- -
    
    Разумеется, в свободных регионах блоков нет, поскольку им не переданы 
страницы физической памяти. Ну а строки с описанием блоков состоят из четырех полей. 
    В первом поле показывается адрес группы страниц с одинаковыми состоянием и 
атрибутами защиты. Например, по адресу Ox779FOOOO передана единственная 
страница (4096 байтов) физической памяти с атрибутом защиты, разрешающим 
только чтение. А по адресу Ox779F1000 присутствует блок размером 8 страниц (32 
768 байтов) переданной памяти с атрибутами, разрешающими и чтение, и 
исполнение. Если бы атрибуты защиты этих блоков совпадали, их можно было бы 
объединить, и тогда на карте памяти появился бы единый элемент размером в 9 
страниц (36 864 байта). 
    Во втором поле сообщается тип физической памяти, которая передана тому или 
иному блоку, расположенному в границах зарезервированного региона. В нем 
появляется одно из 5 возможных значений: free (свободный), private (закрытый), 
mapped (проецируемый), image (образ) и reserve (резервный). Первые четыре 
значения говорят о том, что блоку передана физическая память соответственно из 
страничного файла, файла данных, загруженного ЕХЕ- или DLL-модуля. Если же в 
поле указано значение reserve, блок вообще не связан с физической памятью, но 
может получить ее от операционной системы позже. 
    Чаще всего блоки в пределах одного региона связаны с однотипной физической 
памятью. Однако регион вполне может содержать несколько блоков, связанных с физической 

    ______________________Глава 5. Архитектура памяти в Win32 99 

    памятью разных типов. Например, образ файла, проецируемого в память, может 
быть связан с ЕХЕ- или DLL-файлом. Если Вам понадобится что-то записать на 
одну из страниц в таком регионе с атрибутом защиты PAGE_WRITECOPY или 
PAGE_EXECUTE_WRITECOPY, система подсунет Вашему процессу закрытую копию, 
связанную со страничным файлом, а не с образом файла. Эта новая страница 
получит те же атрибуты, что и исходная, но без защиты по типу «копирование при записи». 
    В третьем поле проставляется размер блока. Все блоки непрерывны в границах 
региона, и никаких разрывов между ними быть не может. 
    В четвертом поле выводятся атрибуты защиты и флаги атрибутов защиты 
текущего блока. Атрибуты защиты блока замещают атрибуты защиты региона, 
содержащего данный блок. Их допустимые значения — те же, что применяются и для 
регионов; кроме того, блоку могут быть присвоены флаги PAGE_GUARD и 
PAGE_NOCACHE, недопустимые для региона. 

    Особенности адресного пространства в Windows 95 

    На рис. 5-7 показана карта адресного пространства при выполнении все той 
же программы VMMAP.EXE, но уже под управлением Windows 95. 

    Базовый   адрес   Атрибут(ы)     Тип        Размер   Блоки   защиты        Описание 

    00000000     Free         4194304 
    00400000     Private        65536    4        ----          C:\ADVWIN3\REL_X86\VMMAP.EXE 
    00400000 Private        12288             -R-- -
    00403000 Private         8192             -RW- -
    00405000 Private         8192             -R-- -
    00407000 Reserve        36864             ---- -
    00410000     Private      1114112    4        ----          стандартная куча процесса 
    00410000 Private        4096             -RW- -
    00410000 Reserve       104480             ---- -
    00410000 Private         4096             -RW- -
    00410000 Reserve        61440             ---- -
    00520000     Private        65535    2        -RW
    00520000 Private         4096             -RW- -
    00521000 Reserve       61440             -RW- -
    00530000     Private      1179648    6        ----          стек потока 
    00530000 Reserve      1077248             ---- -
    00637000 Private        4096             -RW- -
    00638000 Reserve        24576             --— — 
    0063ЕООО Private         4096             ---- -
    0063FOOO Private        4096             -RW- -
    00640000 Reserve        65536             ---- -
    00650000     Private      1114112    4        ---
    00650000 Private        4096             -RW- -
    00650000 Reserve      1044480             ---- -
    00650000 Private         4096             -RW- -
    00650000 Reserve        61440             ---- -
    00760000     Private      4194304    2        -RW
    00760000 Private        65536             -RW- 
    см. след. стр. 

    Рис. 5-7. Образец карты адресного пространства процесса (с указанием 
блоков внутри регионов) в Windows 95 

    100 ______________________________Windows для профессионалов 


    РИС. 5-7 (продолжение) 

    Базовый Атрибут(ы) адрес Тип Размер Блоки защиты Описание 

    00770000 Reserve 4128768 -RW- -
    OOB60000 Free 2001338368 
    78000000 Private 327680 4 ---- C:\WINDOWS\SYSTEM\MSVCRT.DLL 
    78000000 Private 241664 -R-- -
    7803BOOO Private 28672 -RW- -
    78042000 Private 16384 -R-- -
    78046000 Reserve 40960 ---- -
    78050000 Free 133890048 
    80000000 Private 4096 1 ---
    80000000 Reserve 4096 ---- -
    80001000 Private 4096 1 ---
    80001000 Private 4096 -RW- -
    80002000 Private 4096 1 ---
    80002000 Private 4096 -RW- -
    80003000 Private 12288 1 —
    80003000 Private 12288 -RW- -
    80006000 Private 8192 1 ---
    80006000 Private 8192 -RW- -
    80008000 Private 589824 1 ---
    80008000 Private 589824 -RW- -
    80098000 Private 65536 2 ---
    80098000 Private 12288 -RW- -
    8009ВООО Reserve 53248 ---- -
    800А8000 Private 4096 1 ---
    800А8000 Private 4096 -RW- -
    800А9000 Private 454656 1 ---
    800А9000 Private 454656 -RW- -
    80118000 Private 196608 1 ---
    80118000 Private 196608 -RW- -
    80148000 Private 20971520 6 ---
    80148000 Private 331776 -RW- -
    80199000 Reserve 20480 ---- -
    8019ЕООО Private 16384 -RW- -
    801А2000 Reserve 4096 ---- -
    801АЗООО Private 393216 -RW- -
    80203000 Reserve 20205568 ---- -
    81548000 Private 139264 3 ---
    81548000 Reserve 65536 ---- -
    81558000 Private 8192 -RW- -
    8155АООО Reserve 65536 ---- -
    8156АООО Private 1048576 3 ---
    8156АООО Private 53248 -RW- -
    81577000 Reserve 991232 ---- -
    81669000 Private 4096 -RW- -
    8166АООО Private 4194304 3 ---
    8166АООО Private 4096 -RW- -
    8166ВООО Reserve 4186112 ---- -
    'см. след. стр. 


    ______________________ Глава 5. Архитектура памяти в Win32 101 


    РИС. 5-7 (продолжение) 

    Базовый Атрибут(ы) адрес Тип Размер Блоки защиты Описание 

    81А69000 Private 4096 -RW- -
    81А6АООО Private 16384 2 ---
    81А6АООО Private 4096 -RW- -
    81А6ВООО Reserve 12288 -RW- -
    81A6EOOO Private 16384 3 ---
    81A6EOOO .Private 4096 -RW- -
    81A6FOOO Reserve 8192 ---- -
    81A71000 Private 4096 -RW- -
    81A72000 Private 12288 1 ---
    81A72000 Private 12288 -R-- -
    81A75000 Private 12288 1 ---
    81A75000 Private 12288 -R-- -
    81A78000 Private 131072 1 ---
    81A78000 Private 131072 -R-- -
    81A98000 Private 36864 1 -— 
    81A98000 Private 36864 -R-- -
    81AA1000 Private 4096 1 ---
    81AA1000 Private 4096 -RW- -
    81AA2000 Private 2228224 5 -RW
    81AA2000 Private 69632 -RW- -
    81AB3000 Reserve 61440 -RW- -
    81AC2000 Private 12288 -RW- -
    81AC5000 Reserve 2080768 -RW- -
    81CC1000 Private 4096 -RW- -
    81CC2000 Private 4096 1 ---
    81CC2000 Private 4096 -RW- -
    81CC3000 Private 524288 3 ---
    81CC3000 Private 8192 -RW- -
    81CC5000 Reserve 512000 ---- -
    81D42000 Private 4096 -RW- -
    81043000 Private 4096 1 ---
    81D43000 Private 4096 -RW- -
    81D44000 Private 4096 1 ---
    81044000 Private 4096 -RW- -
    81045000 Private 4096 1 ---
    81D45000 Private 4096 -RW- -
    81046000 Private 4096 1 -— 
    81046000 Private 4096 -RW- -
    81D47000 Private 2228224 5 -RW
    81047000 Private 69632 -RW- -
    81058000 Reserve 61440 -RW- -
    81D67000 Private 12288 -RW- -
    8106АООО Reserve 2080768 -RW- -
    81F66000 Private 4096 -RW- -
    81F67000 Private 2162688 5 -RW
    81F67000 Private 4096 -RW- -
    81F68000 Reserve 61440 -RW- -
    см. след. стр. 


    102 ______________________________Windows для профессионалов 


    РИС. 5-7 (продолжение) 

    Базовый Атрибут(ы) адрес Тип Размер Блоки защиты Описание 

    81F77000 Private 20480 -RW- -
    81F7COOO Reserve 2072576 -RW- -
    82176000 Private 4096 -RW- -
    82177000 Private 4096 1 ---
    82177000 Private 4096 -RW- -
    82178000 Private 20480 1 ---
    82178000 Private 20480 -RW- -
    8217DOOO Private 4096 1 ---
    8217DOOO Private 4096 -RW- -
    8217ЕООО Private 4096 1 ---
    8217ЕООО Private 4096 -RW- -
    8217FOOO Private 2097152 3 ---
    8217FOOO Private 4096 -RW- -
    82180000 Reserve 2088960 ---- -
    8237ЕООО Private 4096 -RW- -
    8237FOOO Private 4096 1 ---
    8237FOOO Private 4096 -RW- -
    82380000 Private 4096 1 ---
    82380000 Private 4096 -RW- -
    82381000 Private 4096 1 ---
    82381000 Private 4096 -RW- -
    82382000 Private 4096 1 ---
    82382000 Private 4096 -RW- -
    82383000 Private 4096 1 ---
    82383000 Private 4096 -RW- -
    82384000 Free 16384 
    82388000 Private 4096 1 ---
    82388000 Private 4096 -RW- -
    82389000 Free 172032 
    823ВЗООО Private 4096 1 ---
    823ВЗООО Private 4096 -RW- -
    823В4000 Private 1048576 3 ---
    823В4000 Private 28672 -RW- -
    823ВВООО Reserve 1015808 ---- -
    824ВЗООО Private 4096 -RW- -
    824В4000 Private 1056768 3 ---
    824В4000 Private 4096 -RW- -
    824В5000 Reserve 1048576 ---- -
    825В5000 Private 4096 -RW- -
    825В6000 Free 1030004736 
    BFCOOOOO Private 393216 5 ---
    BFCOOOOO Private 249856 -R-- -
    BFC3DOOO Private 4096 -RW- -
    BFC3EOOO Private 12288 -R-- -
    BFC41000 Private 4096 -RW- -
    см. след. стр. 


    ______________________Глава 5. Архитектура памяти в Win32 103 


    РИС. 5-7 (продолжение) 

    Базовый  адрес   Атрибут(ы)     Тип         Размер   Блоки   защиты        Описание 

    BFC42000 Private       122880             -R-- -
    BFC60000     Free         2031616 
    BFE50000     Private        45056    5        ---
    BFE50000 Private        24576             -R-- -
    BFE56000 Private         4096             -RW- -
    BFE57000 Private         4096             -R-- -
    BFE58000 Private         4096             -RW- -
    BFE59000 Private         8192             -R-- -
    BFE5BOOO     Free           20480 
    BFE60000     Private        65536    3        ---
    BFE60000 Private        40960             -R-- -
    BFE6AOOO Private         8192             -RW- -
    BFE6COOO Private        16384             -R-- -
    BFE70000     Free          393216 
    BFEDOOOO     Private        57344    3        ----          C:\WINDOWS\SYSTEM\ADVAPI32.DLL 
    BFEDOOOO Private        40960             -R-- -
    BFEDAOOO Private         8192             -RW- -
    BFEDCOOO Private         8192             -R-- -
    BFEDEOOO     Free          335872 
    BFF30000     Private       151552    5        ----          C:\WINDOWS\SYSTEM\GDI32.DLL 
    BFF30000 Private       110592             -R-- -
    BFF4BOOO Private        12288             -RW- -
    BFF4EOOO Private        12288             -R-- -
    BFF51000 Private         4096             -RW- -
    BFF52000 Private        12288             -R-- -
    BFF55000     Free           45056 
    BFF60000     Private        61440    3        ----          C:\WINDOWS\SYSTEM\USER32.DLL 
    BFF60000 Private        28672             -R-- -
    BFF67000 Private         4096             -RW- -
    BFF68000 Private        28672             -R-- -
    BFF6FOOO     Free            4096 
    BFF70000     Private       585728    5        ----          C:\WINDOWS\SYSTEM\KERNEL32.DLL 
    BFF70000 Private       303104             -R-- -
    BFFBAOOO Reserve         8192             ---- -
    BFFBCOOO Private        16384             -RW- -
    BFFCOOOO Private        98304             -R--' -
    BFFD8000 Reserve       159744        '    ---- -
    BFFFFOOO     Free            4096 

    Главное отличие двух карт адресного пространства в том, что под 
управлением Windows 95 информации получаешь значительно меньше. Например, о 
регионах и блоках можно узнать лишь, свободны они, зарезервированы или 
закрыты. А выяснить, какой у них статус — mapped или image, нельзя; Windows 95 
не позволяет получить дополнительную информацию, по которой можно было бы 
судить, какой именно тип физической памяти связан с регионом — проецируемый в 
память файл или образ ЕХЕ- или DLL-файла. 

    104 ______________________________Windows для профессионалов 

    Наверное, Вы заметили, что размер большинства регионов кратен 64 Кб (это 
значение определяется гранулярностью выделения ресурсов). Если размеры блоков, 
составляющих регион, не дают в сумме этой величины, то в конце региона часто 
появляется резервный блок адресного пространства. Его размер выбирается 
системой так, чтобы довести общий объем региона до величины, кратной 64 Кб. 
Например, регион, который начинается с адреса 0х00520000, включает в себя 2 
блока: четырехкилобайтовый блок переданной памяти и резервный блок, занимающий 
60 Кб адресного пространства. 
    Заметьте также, что на последней карте нет атрибутов защиты, разрешающих 
испол нение или копирование при записи, поскольку Windows 95 не поддерживает 
их. Кроме того, она не поддерживает и флаги атрибутов защиты (PAGE_GUARD и 
PAGE_NOCACHE). Из за этого, кстати, программе VMMAP.EXE приходится 
использовать более сложный метол, чтобы определить, не выделен ли данный 
регион под стек потока. 
    И последнее. В Windows 95 (в отличие от Windows NT) можно исследовать 
регион адресного пространства OxSOOOOOOO-OxBFFPFFFF. Это раздел, в котором 
находится адресное пространство, общее для всех Wn'132-приложений. На карте 
отчетливо видно, что в него загружены 4 системных DLL, и поэтому они доступны 
любому Win32-npoueccy. 