
- •1.1 Основы программирования в операционной системе Windows
- •1.1.1 Вызов функций api
- •1.1.2 Структура программы
- •1.2 Вопросы системного программирования в Windows
- •1.2.1 Страничная и сегментная адресация.
- •1.2.2 Адресное пространство процесса.
- •2.1 Управление процессами
- •2.2 Процессы и потоки в Windows
- •2.3 Создание процессов
- •2.4 Определение исполняемого образа и командной строки
- •2.5 Идентификация процессов
- •3.1 Создание потока. Функция CreateThread
- •3.2. Завершение потока
- •3.3 Другие функции работы с потоками
- •3.4 Структура context
- •3.5 Приоритеты потоков
- •4.1 Объект critical_section
- •4.2 Мьютексы
- •4.3 Семафоры
- •5.1 События
- •7.1 Кучи
- •7.2 Управление памятью кучи
- •Другие функции для работы с кучей
- •Резюме по управлению кучей
- •Отображение адресного пространства процесса в объекты отображения
- •Что такое импорт
- •Явная загрузка dll
- •Явное подключение экспортируемого идентификатора
- •10.1 Управление файлами и каталогами Создание и открытие файлов
- •10.2 Управление каталогами
- •10.3 Другие методы получения атрибутов файлов и каталогов
- •11.1 Блокировка файлов
- •11.2 Реестр
- •12.1 Стандартные устройства и консольный ввод-вывод
- •12.2 Асинхронный ввод-вывод и порты завершения
- •Параметры
- •Цели системы безопасности
- •Параметры
- •Аварийное завершение
- •Использование именованных каналов
- •Параметры
- •Наблюдение за сообщениями в именованном канале
- •Параметры
7.1 Кучи
Win32 поддерживает области памяти в виде куч (heaps). Процесс может содержать несколько куч, и из них разработчик выделяет память.
Часто достаточно одной кучи, но по приведенным ниже причинам используется и много куч. Если достаточно одной кучи, просто используйте функции библиотеки С для управления памятью (malloc, free, calloc, realloc).
Кучи являются объектами Win32, поэтому они имеют дескрипторы. Дескриптор кучи необходимо знать, когда выделяется память. Каждый процесс имеет собственную кучу, принятую по умолчанию, к которой обращается функция malloc, а следующая функция возвращает ее дескриптор.
HANDLE GetProcessHeap (VOID)
Возвращаемое значение: дескриптор кучи процесса; NULL в случае неудачи.
Заметим, что в данном случае для указания на ошибку возвращается значение NULL, а не INVALID_HANDLE_VALUE, как в функции CreateFile.
Программа также может создавать особые кучи. Это относится к тем случаям, когда необходимы отдельные кучи для резервирования отдельных структур данных. Ниже описаны преимущества отдельных куч.
• Справедливость распределения. Ни один поток не может получить больше памяти, чем зарезервировано для его кучи. В частности, утечка памяти, вызванная программой, не учитывающей свободные и больше не используемые элементы данных, повлияет только на поток процесса.
• Многопоточное быстродействие. Благодаря предоставлению каждому потоку отдельной кучи соревнование между потоками сокращается, что может существенно повысить быстродействие.
• Эффективность резервирования. Резервирование элементов данных фиксированного размера в маленькой куче значительно более эффективно, чем резервирование множества элементов разных размеров в одной большой куче. Также снижается фрагментация памяти. Кроме того, выделение каждому потоку отдельной кучи упрощает синхронизацию, что дает дополнительный выигрыш.
• Эффективность освобождения памяти. Вся куча и все структуры данных, размещенные в ней, могут быть освобождены одним вызовом функции. При этом также освобождается и вся выделенная, но потерянная память в куче.
• Эффективная локализация ссылок. Расположение структуры данных в маленькой куче гарантирует, что ее элементы будут сосредоточены в сравнительно небольшом количестве страниц, что потенциально сокращает страничные ошибки при обработке структуры.
Ценность этих преимуществ изменяется в зависимости от приложения, и многие программисты будут пользоваться только кучей процесса и библиотекой С. В любом случае, следующие две функции создают и уничтожают кучи.
Начальный размер кучи, который может быть нулевым и всегда округляется до числа, кратного размеру страницы, определяет объем физической памяти (в файле подкачки), первоначально отведенный куче. Когда программа выходит за границы начального размера, автоматически выделяются дополнительные страницы вплоть до максимального предела. Так как файл подкачки является ограниченным ресурсом, отложенное выделение удобно в случаях, когда размер кучи заранее не известен. Ненулевое значение переменной dwMaximumSize определяет предел для динамического повышения объема кучи. Куча процесса также будет динамически расти.
HANDLE HeapCreate ( DWORD flOptions,
SIZE_T dwInitialSize, SIZE_T dwMaximumSize);
Возвращаемое значение: дескриптор кучи или NULL в случае ошибки.
Два поля размера имеют тип size_t, а не dword. Тип size_t определен таким образом, что может быть 32-разрядным или 64-разрядным беззнаковым целым, в зависимости от флагов компилятора (_WIN32 или _WIN64). Тип size_t был введен для обеспечения возможности перехода к WIN64.
Переменная flOptions является комбинацией двух флагов.
• HEAP_GENERATE_EXCEPTIONS— при этом значении неудачные попытки выделения памяти вызывают исключения, которые будут обработаны структурным обработчиком исключений (Structured Exception Handler — SEH,). Функция HeapCreate сама по себе не вызывает исключений; если этот флаг установлен, исключение вызывают при неудаче такие функции, как HeapAlloc.
• HEAP_NO_SERIALIZE — установка этого флага в некоторых случаях позволяет получить небольшое повышение быстродействия. Следует сказать также несколько слов о dwMaximumSize.
• Если значение dwMaximumSize. не равно нулю, виртуальное адресное пространство выделяется и в том случае, когда весь указанный объем выделить невозможно. Это максимальный размер кучи, которая называется невозрастающей. Данная опция ограничивает размер кучи, возможно, для достижения справедливости распределения ресурсов, о которой упоминалось ранее.
• С другой стороны, если значение dwMaximumSize. — нуль, то куча является возрастающей за пределы начального размера. Эта граница определяется доступным виртуальным адресным пространством, часть которого может быть предоставлена другим кучам, и пространством файла подкачки.
Отметим, что кучи не имеют атрибутов безопасности, так как они недоступны извне процесса.
Для уничтожения всей кучи используйте функцию HeapDestroy. Это другое исключение из общего правила о том, что функция CloseHandle применяется для удаления всех ненужных дескрипторов.
BOOL HeapDestroy (HANDLE hHeap);
Переменная hHeap должна указывать на кучу, созданную функцией HeapCreate. Будьте осторожны, не уничтожьте кучу процесса (полученную функцией GetProcessHeap). Уничтожение кучи освобождает пространство виртуальной памяти и физическую память в файле подкачки. Разумеется, грамотно спроектированные программы должны освобождать кучи, которые больше не используются.
Уничтожение кучи — это также быстрый способ освободить структуру данных без необходимости уничтожать каждый элемент отдельно, хотя экземпляры объектов С++ таким образом не будут уничтожены, поскольку их деструкторы не вызываются. Уничтожение кучи имеет ряд преимуществ.
1. Нет необходимости писать код для поэлементного обхода структуры.
2. Нет необходимости освобождать каждый отдельный элемент.
3. Система не тратит время на поддержку кучи с того момента, когда все структуры данных освобождаются одним системным вызовом.