Заметки по WinAPI

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

    • 4 ГБ на x32 и 16 экзобайт на x64
    • делится на следующие области (от 2000)
      • для выявления нулевых указателей (от 0x00000000 до 0x0000FFFF ) 64 KB
        • любое обращение туда - ошибка
      • для кода и данных пользовательского режима
        • располагается основной объем данных процесса, подгружаемые DLL и EXE модули
        • ни один процесс не может получить доступ к этой области другого процесса
        • ключ /3GB увеличивает его размер до 3 ГБ на х32 (без него - 1 ГБ)
      • закрытый размером 64 KB
        • его основная задача - упростить проверку того, что работа в области пользовательского режима мы не "залезем" в память для кода и данных режима ядра
      • для кода и данных режима ядра
        • сюда помещается код операционной системы, в том числе драйверы устрйств и код низкоуровневого управления потоками, файловой системой, сетевой поддержкой.
        • все здесь доступно любому процессу, но только коду в режиме ядра (пользовательское обращение вызовет ошибку доступа)
  • Регионы в адресном пространстве

    • аллоцирование при помощи VirtualAlloc в ВАПе (резервирование) только гранулярно (кратно 64КБ)
    • далее нужно делать коммит при помощи той же функции (тут уже обязательна кратность страницам (4 КБ) )
  • что вообще происходит при запуске приложения

    • система при запуске EXE файла считает этот EXE файлом куском памяти этого процесса и ничего никуда не копирует
  • стек потока

    • он начинается в бОльших адресах и заканчивается на 0х08000000
    • притом на странице 0х08001000 он кинет исключение StackOverflow
    • и если исключение проигнорировать и продолжить работу то под 0x08000000 не выделяется физ память, потому все грохнется.
    • у Win 2000 есть одна опасность - у них нет ограничителя на обращения в "отрицательные" области стека, и там произойдут обращения к, возможно, корректным олбластям памяти и никаких явных ошибок не будет видно
    • поначалу все ставится так, что стек размеров 2 страницы, притом на страницу в которую растет стек ставится GUARD флаг, если до него дойдет - стек начнет расти. Исключение - 0x08001000 - на эту границу gurad никогда не ставится.
  • проецируемые файлы в память

    • вместо того чтобы копировать себе часть/весь файл мы резервируем кусок адресного пространства, и его "перенаправляем" на файл лежащий на диске (никаких копирований)
    • это позволяет
      • быстро подгружать EXE и DLL части
      • доступ к файлу с данными на диске без файлового считывания/вывода
      • разделение доступа к этим данным между несколькими процессами на одной машине
    • немного лирики о загрузке DLL
      • есть так называемый "базовый адрес" (по умолчанию 0x10000000, но в DLL может быть указан в ручную)
      • если он занят или в нем не удается выделить блок нужного размера
        • если DLL типа FIXED то вообще fail, она не загрузится
        • если не FIXED то она загрузится в найденный блок достаточного размера НО произойдет модификация адресов внутри DLL а это в Win2000 уйдет доп физ память и нкоторое время
  • кучи

    • используются обычно для аллоцирования большого количества мелких объектов
    • у процесса есть стандартная куча, по умолчания 1 МБ // ее используют Windows функции
    • причины использования
      • защита компонентов
      • более эффективное управление памятью
      • локальный доступ
      • исключение издержек
      • быстрое освобождение памяти в куче
    • Low-Fragmentation Heap
      • опция, которую можно включить для дефолтной кучи процесса или своей кучи
      • как сделать
        • получаем handle // ::CreateHeap или ::GetProcessHeap
        • устанавлимваем нужный флаг // ::HeapSetInformation
      • обозначает "при запросе менее 16KB он пытается найти самую маленькую область куда объект влезет и выделить там"
      • не дружит с HEAP_NO_SERIALIZE
      • начиная с Vista включена по дефолту.