Кафедра ИСиТ УО ВГТУ
  • Специальности
    • Экономика электронного бизнеса
    • Информационные системы
    • Information Control Systems
  • Каталог
  • Сайт кафедры
  • Сервисы
    • GitLab
    • ownCloud
    • JupyterHub
    • JupyterHub 2
    • VNC
    • Soft
  1. ИСиТ
  2. Системное программирование
  3. Теория
  4. Управление памятью в Windows
  • ИСиТ
    • АОС
      • Теория
        • Введение в операционные системы
        • Управление памятью
        • Управление процессами
        • Система ввода-вывода
        • Информационная безопасность
        • Виртуализация
      • Практика
    • РВПсИПП
      • Теория
        • Настройка среды разработки для PHP
        • Разработка web-приложений на базе фреймворков
        • Основы Laravel
        • Шаблоны в Laravel
        • Модели и базы данных в Laravel
        • Формы и валидация в Laravel
        • Аутентификация и авторизация в Laravel
        • Создание REST API в Laravel
        • Работа с файлами и изображениями в Laravel
        • Тестирование и отладка в Laravel
        • Введение в фреймворк Symfony
        • Маршруты и контроллеры в Symfony
        • Шаблоны и Twig в Symfony
        • Формы и валидация в Symfony
        • Доступ к базам данных в Symfony
        • Аутентификация и авторизация в Symfony
        • Сервисы и зависимости в Symfony
        • Создание REST API в Symfony
        • Работа с файлами и медиа в Symfony
        • Сравнение и выбор фреймворка
        • Развертывание веб-приложения
      • Практика
        • Лаб. работа 1 “Создание нового приложения Laravel”
        • Лаб. работа 2 “Добавление главной страницы и базовых маршрутов”
        • Лаб. работа 3 “Создание моделей, миграций и сидеров”
        • Лаб. работа 4 “Создание индексных страниц и пагинация”
        • Лаб. работа 5 “Создание форм для работы с сущностями”
        • Лаб. работа 6 “Работа с файлами (эмуляция S3-хранилища)”
        • Лаб. работа “Создание маршрутов в Laravel”
        • Лаб. работа “Работа с базами данных в Laravel”
        • Лаб. работа “Работа с формами в Laravel”
        • Лаб. работа “Аутентификация и авторизация в Laravel”
        • Лаб. работа “Работа с файлами в Laravel”
        • Лаб. работа “Тестирование и оптимизация в Laravel”
        • Лаб. работа “Создание REST API в Laravel”
        • Лаб. работа “Основы Symfony”
        • Лаб. работа “Шаблоны и представления в Symfony”
        • Лаб. работа “Работа с базами данных в Symfony”
        • Лаб. работа “Фомы и аутентификация в Symfony”
        • Лаб. работа “Сервисы и зависимости в Symfony”
        • Лаб. работа “REST API в Symfony”
        • Лаб. работа “Работа с медиа контентом в Symfony”
        • Лаб. работа “Создание и развертывание проекта”
    • ПСП
      • Теория
        • Введение
        • Протокол HTTP
        • Программирование с использованием сокетов
        • Введение в PHP
        • Работа с базами данных в PHP
        • Объектно-ориентированные возможности PHP
        • Настройка среды разработки для PHP
        • Разработка web-приложений на базе фреймворков
      • Практика
        • Программное обеспечение
        • Регистрация в JupyterHub
        • Лаб. работа “Почтовые протоколы”
        • Лаб. работа “Протокол FTP”
        • Лаб. работа “Протокол HTTP”
        • Лаб. работа “Программирование сетевых приложений с использованием сокетов”
        • Лаб. работа “Основы PHP”
        • Лаб. работа “Массивы в PHP”
        • Лаб. работа “Создание веб-приложений с использованием Slim”
    • Компьютерные сети
      • Теория
        • Введение в компьютерные сети
        • Топологии сетей
        • Кодирование и мультиплексирование
        • Стеки протоколов
        • Адресация в компьютерных сетях
        • Система доменных имен (DNS)
        • Программирование с использованием сокетов
        • Введение в PHP
        • Протокол HTTP
        • Введение в компьютерные сети
      • Практика
        • Программное обеспечение
        • Регистрация в JupyterHub
        • Лаб. работа “Почтовые протоколы”
        • Лаб. работа “Протокол FTP”
        • Лаб. работа “Протокол HTTP”
        • Лаб. работа “Программирование сетевых приложений с использованием сокетов”
        • Лаб. работа “Основы PHP”
        • Лаб работа “Массивы в PHP”
    • РиОИИС
      • Теория
        • Классификация оптимизационных задач
        • Генетические алгоритмы
        • Системы массового обслуживания
        • Теория игр
        • Машинное обучение
        • Глубокое обучение (Deep learning)
        • Основы функционального программирования
        • Основы программирования на Haskell
        • Введение в логическое программирование
        • Инференция и рассуждения в логическом программировании
        • Разработка экспертных систем
        • Интеллектуальные системы и их архитектура
        • Веб-скрэйпинг
        • Сбор данных с открытых API
      • Практика
        • JupyterHub
        • Лаб. работа “Методы одномерной оптимизации”
        • Лаб. работа “Методы многомерной оптимизации”
        • Лаб. работа “Функции в Python”
        • Лаб. работа “Рекурсия в Python”
        • Лаб. работа “Итераторы в Python”
        • Лаб. работа “Генетические алгоритмы”
        • Лаб. работа “Haskell”
        • Лаб. работа “Логическое программирование”
        • Лаб. работа “Сбор данных с помощью веб-скрейпинга”
    • КСКР
      • Практика
        • Лаб. работа “Одномерные и двумерные массивы в C#”
        • Лаб. работа “Обращение матриц в C#”
    • Системное программирование
      • Теория
        • Управление памятью в Windows
        • Файловые операции в Windows
        • Управление процессами в Windows
        • Графический интерфейс Windows
        • ОС Unix
      • Практика
        • Лаб. работа “Работа с динамической памятью в Windows”
        • Лаб. работа “Операции с файлами в Windows”
        • Лаб. работа “Управление процессами в Windows”
        • Лаб. работа “Работа с виртуальной машиной Linux”
        • Лаб. работа “Язык командного энтерпритатора Shell”
        • Лаб. работа “Работа с файлами в Linux”
        • Лаб. работа “Работа с процессами в Linux”

Содержание

  • Виртуальная память
    • Виртуальная адресация
    • Физическая память и страничный файл
    • Страницы памяти
    • Отображение виртуальной памяти
    • Защита памяти
    • Управление виртуальной памятью
  • Управление динамической памятью
    • Выделение памяти с использованием malloc и free (C/C++)
    • Выделение памяти с использованием функции VirtualAlloc (WinAPI)
    • Выделение и освобождение памяти с использованием C++ операторов new и delete
  • Стек и куча
    • Стек (Stack)
    • Куча (Heap)
    • Сравнение стека и кучи
  • Функции для работы со стеком
    • GetCurrentThreadStackLimits (Windows 8.1 и более поздние версии)
    • RtlCaptureContext (Windows XP и более поздние версии)
    • VirtualQuery (Windows XP и более поздние версии)
    • SetThreadStackGuarantee (Windows 8 и более поздние версии)
    • StackWalk64 (DbgHelp API)
  • Функции для работы с кучей
    • HeapCreate
    • HeapAlloc
    • HeapFree
    • HeapReAlloc
    • HeapDestroy
    • HeapSize
    • HeapValidate
    • Пример 1: Создание кучи и выделение памяти
    • Пример 2: Выделение строки в куче
  • Отображение файлов на адресное пространство
    • Создание файла для сопоставления
    • Создание отображения файла в памяти
    • Отображение файла в виртуальную память
    • Использование данных
    • Освобождение ресурсов

Другие форматы

  • RevealJS
  1. ИСиТ
  2. Системное программирование
  3. Теория
  4. Управление памятью в Windows

Управление памятью в Windows

Системное программирование
Теория
Автор
принадлежность

Бизюк Андрей

ВГТУ

Дата публикации

3 декабря 2024 г.

Виртуальная память

Виртуальная память - это важная часть операционных систем, включая Windows. Она представляет собой механизм, позволяющий приложениям, работать с большими объемами памяти, чем физически доступно на компьютере, и обеспечивает изоляцию процессов друг от друга. Вот основные аспекты виртуальной памяти в Windows:

Виртуальная адресация

Каждому процессу в Windows предоставляется свое собственное виртуальное адресное пространство. Это означает, что каждый процесс видит свою собственную непрерывную область адресов, начиная с нуля. Этот механизм позволяет изолировать процессы друг от друга, так что один процесс не может напрямую обратиться к памяти другого процесса.

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

Виртуальная память Windows состоит из физической оперативной памяти (RAM) и страничного файла на диске. Если физическая память заполняется, то часть данных может быть перемещена в страничный файл, освобождая место для новых данных. Этот процесс называется “подкачкой” (paging).

Страницы памяти

Виртуальная память разбивается на небольшие блоки, называемые страницами памяти. Размер страницы обычно составляет 4 КБ. Windows использует систему управления таблицами страниц (Page Table) для отображения виртуальных адресов на физические адреса или на адреса в страничном файле.

Отображение виртуальной памяти

Когда процесс обращается к виртуальной памяти, операционная система Windows преобразует виртуальный адрес в соответствующий физический адрес. Если требуемая страница находится в физической памяти, это происходит незаметно. Если страница находится в страничном файле, она должна быть загружена в физическую память перед доступом к ней.

Защита памяти

Виртуальная память Windows также обеспечивает механизмы защиты. Каждая страница памяти может иметь разрешения на чтение, запись и выполнение. Это позволяет операционной системе и программам контролировать доступ к памяти и предотвращать некорректное или вредоносное поведение.

Управление виртуальной памятью

Операционная система Windows автоматически управляет виртуальной памятью, включая подкачку данных между физической памятью и страничным файлом. Программисты обычно не заботятся о деталях управления виртуальной памятью, но могут использовать API для запроса дополнительной памяти (например, функции VirtualAlloc) и управления защитой памяти (например, функции VirtualProtect).

Управление динамической памятью

Управление памятью в Windows может быть выполнено с использованием различных функций и API операционной системы. Давайте рассмотрим несколько примеров кода на языке C/C++ для выделения и освобождения памяти в Windows.

Выделение памяти с использованием malloc и free (C/C++)

#include <stdio.h>
#include <stdlib.h>

int main() {
    // Выделение памяти под массив целых чисел
    int *arr = (int*)malloc(5 * sizeof(int));

    if (arr == NULL) {
        printf("Не удалось выделить память\n");
        return 1;
    }

    // Использование выделенной памяти
    for (int i = 0; i < 5; i++) {
        arr[i] = i * 10;
    }

    // Освобождение памяти после использования
    free(arr);

    return 0;
}

В этом примере мы используем функции malloc для выделения памяти под массив целых чисел и free для освобождения этой памяти после ее использования.

Выделение памяти с использованием функции VirtualAlloc (WinAPI)

#include <Windows.h>
#include <stdio.h>

int main() {
    // Выделение 1 мегабайта (1048576 байт) виртуальной памяти
    LPVOID mem = VirtualAlloc(NULL, 1048576, MEM_COMMIT, PAGE_READWRITE);

    if (mem == NULL) {
        printf("Не удалось выделить виртуальную память\n");
        return 1;
    }

    // Использование выделенной виртуальной памяти

    // Освобождение виртуальной памяти
    VirtualFree(mem, 0, MEM_RELEASE);

    return 0;
}

Здесь мы используем функцию VirtualAlloc из библиотеки WinAPI для выделения виртуальной памяти. После использования памяти мы освобождаем ее с помощью функции VirtualFree.

Выделение и освобождение памяти с использованием C++ операторов new и delete

#include <iostream>
#include <windows.h>

int main() {
    SetConsoleOutputCP(1251);
    // Выделение памяти под одно целое число
    int *num = new int;

    // Использование выделенной памяти
    *num = 42;
    std::cout << "Значение: " << *num << std::endl;

    // Освобождение памяти
    delete num;

    return 0;
}

Стек и куча

Стек и куча - это две основные области памяти, используемые в программах для хранения данных и управления памятью. Они имеют разные характеристики и предназначены для разных целей. Давайте рассмотрим их более подробно:

Стек (Stack)

  • Характеристики:
    • Ограниченный по размеру.
    • Доступ к данным выполняется в порядке “первым вошел, последним вышел” (LIFO - Last-In, First-Out).
    • Часто фиксированный размер стека определяется на этапе компиляции.
  • Использование:
    • Хранит локальные переменные функций и адреса возврата после вызова функций.
    • Используется для управления вызовами функций (стек вызовов).
  • Жизненный цикл данных:
    • Данные, хранящиеся в стеке, автоматически удаляются при завершении функции, в которой они определены.
    • Ограниченное время жизни.
  • Примеры языков:
    • Стек используется в C, C++, Java (для вызовов методов), Python (для вызовов функций).

Куча (Heap)

  • Характеристики:
    • Динамически расширяемая область памяти.
    • Доступ к данным происходит в произвольном порядке.
    • Размер кучи ограничен объемом доступной физической и виртуальной памяти.
  • Использование:
    • Хранит данные, которые могут иметь долгий или неопределенный срок жизни, такие как объекты, созданные динамически.
  • Жизненный цикл данных:
    • Данные, хранящиеся в куче, существуют до тех пор, пока на них есть указатели, и могут быть освобождены вручную (например, с помощью free в C/C++ или сборщика мусора в других языках).
  • Примеры языков:
    • Куча используется в C, C++, C#, Java (для объектов, созданных с помощью new), Python (с использованием модуля gc для сборки мусора).

Сравнение стека и кучи

  • Стек обычно быстрее доступен для чтения и записи, чем куча.

  • Куча предоставляет более гибкое управление памятью, но требует явного освобождения ресурсов.

  • Стек обеспечивает управление временем жизни данных автоматически, в то время как в куче это делается вручную.

  • Использование стека ограничено, поэтому он лучше подходит для хранения данных с известным временем жизни, в то время как куча подходит для данных с неопределенным или долгим временем жизни.

  • Оба механизма имеют свои применения и зависят от конкретных требований программы.

Функции для работы со стеком

Windows предоставляет набор функций и API для работы со стеком приложения. Эти функции позволяют программам управлять стеком вызовов функций, а также получать информацию о текущем состоянии стека. Вот некоторые из наиболее часто используемых функций Windows для работы со стеком:

GetCurrentThreadStackLimits (Windows 8.1 и более поздние версии)

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

Пример использования:

void GetStackLimits() {
    ULONG_PTR lowLimit, highLimit;
    GetCurrentThreadStackLimits(&lowLimit, &highLimit);
    printf("Low Limit: 0x%llx\n", lowLimit);
    printf("High Limit: 0x%llx\n", highLimit);
}

RtlCaptureContext (Windows XP и более поздние версии)

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

Пример использования:

CONTEXT context;
RtlCaptureContext(&context);
// Теперь у вас есть информация о контексте выполнения текущего потока

VirtualQuery (Windows XP и более поздние версии)

Эта функция позволяет получить информацию о виртуальной памяти, включая стек. Вы можете использовать ее для определения границ стеков разных потоков или для анализа виртуальной памяти вашего процесса.

Пример использования:

MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(&someAddress, &mbi, sizeof(mbi));
// Теперь вы можете получить информацию о найденной памяти, включая стек

SetThreadStackGuarantee (Windows 8 и более поздние версии)

Эта функция позволяет установить минимальный размер стека для потока. Это может быть полезно, чтобы предотвратить переполнение стека в потоках с большой глубиной вызовов.

Пример использования:

DWORD stackSize = 0x10000; // 64 КБ
SetThreadStackGuarantee(&stackSize);

StackWalk64 (DbgHelp API)

Эта функция из библиотеки DbgHelp API позволяет выполнять обход стека вызовов функций для получения информации о вызовах и адресах функций. Она полезна при создании отладочных и профилирующих инструментов.

Пример использования:

STACKFRAME64 stackFrame;
// Настройка параметров и выполнение обхода стека

Функции для работы с кучей

WinAPI предоставляет ряд функций для работы с кучей (памятью, выделяемой в куче). Основные функции включают в себя HeapCreate, HeapAlloc, HeapFree, HeapReAlloc и HeapDestroy. Давайте рассмотрим эти функции более подробно:

HeapCreate

  • Создает новую кучу.

  • Синтаксис: HANDLE HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize);

  • Пример:

    HANDLE hHeap = HeapCreate(0, 0, 0);

HeapAlloc

  • Выделяет блок памяти из кучи.

  • Синтаксис: LPVOID HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);

  • Пример:

    int* pData = (int*)HeapAlloc(hHeap, 0, sizeof(int) * 10);

HeapFree

  • Освобождает блок памяти, выделенный ранее с помощью HeapAlloc.

  • Синтаксис: BOOL HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);

  • Пример:

    HeapFree(hHeap, 0, pData);

HeapReAlloc

  • Изменяет размер выделенного блока памяти в куче.

  • Синтаксис: LPVOID HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, SIZE_T dwBytes);

  • Пример:

    pData = (int*)HeapReAlloc(hHeap, 0, pData, sizeof(int) * 20);

HeapDestroy

  • Уничтожает кучу и освобождает все связанные с ней ресурсы.

  • Синтаксис: BOOL HeapDestroy(HANDLE hHeap);

  • Пример:

    HeapDestroy(hHeap);

HeapSize

  • Возвращает размер выделенного блока памяти в куче.

  • Синтаксис: SIZE_T HeapSize(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem);

  • Пример:

    SIZE_T size = HeapSize(hHeap, 0, pData);

HeapValidate

  • Проверяет целостность кучи и выделенных блоков.

  • Синтаксис: BOOL HeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem);

  • Пример:

    if (HeapValidate(hHeap, 0, pData)) {
        printf("Куча валидна.\n");
    } else {
        printf("Куча повреждена.\n");
    }

Пример 1: Создание кучи и выделение памяти

#include <Windows.h>
#include <stdio.h>

int main() {
    SetConsoleOutputCP(1251);
    // Создание кучи
    HANDLE hHeap = HeapCreate(0, 0, 0);

    if (hHeap == NULL) {
        printf("Не удалось создать кучу\n");
        return 1;
    }

    // Выделение памяти из кучи
    int *data = (int*)HeapAlloc(hHeap, 0, sizeof(int) * 5);

    if (data == NULL) {
        printf("Не удалось выделить память из кучи\n");
        HeapDestroy(hHeap);
        return 1;
    }

    // Использование выделенной памяти
    for (int i = 0; i < 5; i++) {
        data[i] = i * 10;
    }

    // Освобождение памяти
    HeapFree(hHeap, 0, data);

    // Уничтожение кучи
    HeapDestroy(hHeap);

    return 0;
}

В этом примере мы создаем кучу с помощью HeapCreate, выделяем память из кучи с помощью HeapAlloc, используем эту память и освобождаем ее с помощью HeapFree, а затем уничтожаем кучу с помощью HeapDestroy.

Пример 2: Выделение строки в куче

#include <Windows.h>
#include <stdio.h>

int main() {
    SetConsoleOutputCP(1251);
    // Создание кучи
    HANDLE hHeap = HeapCreate(0, 0, 0);

    if (hHeap == NULL) {
        printf("Не удалось создать кучу\n");
        return 1;
    }

    // Выделение строки в куче
    char *str = (char*)HeapAlloc(hHeap, 0, 256);

    if (str == NULL) {
        printf("Не удалось выделить память для строки\n");
        HeapDestroy(hHeap);
        return 1;
    }

    // Копирование строки в выделенную память
    strcpy_s(str, 256, "Пример строки в куче");

    // Использование строки

    // Освобождение памяти
    HeapFree(hHeap, 0, str);

    // Уничтожение кучи
    HeapDestroy(hHeap);

    return 0;
}

В этом примере мы выделяем память для строки в куче, копируем строку в эту память, используем ее и освобождаем память.

Отображение файлов на адресное пространство

File mapping (сопоставление файла) в WinAPI - это механизм, который позволяет отображать содержимое файла в виртуальную память процесса. Это может быть полезно для обмена данными между процессами, создания разделяемой памяти или для улучшения производительности при доступе к большим файлам. Давайте рассмотрим основы использования file mapping в WinAPI:

Создание файла для сопоставления

Сначала необходимо создать или открыть файл, который вы хотите сопоставить. Это можно сделать с помощью функций, таких как CreateFile или OpenFile. Например:

HANDLE hFile = CreateFile(
    L"C:\\example.txt",           // Имя файла
    GENERIC_READ | GENERIC_WRITE, // Режим доступа
    0,                            // Атрибуты файла
    NULL,                         // Дескриптор безопасности
    OPEN_ALWAYS,                  // Действие при открытии (создать, если не существует)
    FILE_ATTRIBUTE_NORMAL,        // Атрибуты файла
    NULL                          // Шаблон для атрибутов
);

Создание отображения файла в памяти

Затем создайте отображение файла в виртуальную память с помощью функции CreateFileMapping. Это создает объект отображения файла, который может быть использован для доступа к содержимому файла:

HANDLE hMapFile = CreateFileMapping(
    hFile,                   // Дескриптор файла
    NULL,                    // Атрибуты безопасности (можно использовать NULL)
    PAGE_READWRITE,          // Режим доступа к файлу в отображении
    0,                       // Размер отображения файла (0 - весь файл)
    0,                       // Высший значащий байт размера файла
    NULL                     // Имя отображения файла (можно использовать NULL)
);

Отображение файла в виртуальную память

Завершите процесс сопоставления файла, отображая его в виртуальную память с помощью функции MapViewOfFile:

LPVOID pData = MapViewOfFile(
    hMapFile,              // Дескриптор отображения файла
    FILE_MAP_ALL_ACCESS,   // Режим доступа к отображению
    0,                     // Смещение в файле
    0,                     // Начальный байт отображения
    0                      // Размер отображения (0 - весь файл)
);

Использование данных

Теперь pData указывает на начало отображения файла в виртуальной памяти. Вы можете работать с данными, как с обычной памятью.

Освобождение ресурсов

После завершения работы с данными не забудьте освободить ресурсы:

UnmapViewOfFile(pData);  // Освобождение отображения файла
CloseHandle(hFile);      // Закрытие дескриптора файла
CloseHandle(hMapFile);   // Закрытие дескриптора отображения файла
Наверх
Теория
Файловые операции в Windows