Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
13
Добавлен:
26.02.2022
Размер:
142.4 Кб
Скачать

ЛР3 Вариант 1

Задание

Реализовать программу для изучения фрагментации виртуальной памяти.

1.Получить и напечатать общий и доступный объем виртуальной памяти (ВП) при помощи функции GlobalMemoryStatusEx(). Пронаблюдать состояние памяти процесса при помощи VMMap.

2.Использовать всю доступную ВП, выделяя функцией VirtualAlloc() области размером по 100 МБ, пока это удается. Указатели на выделяемые области сохранять в массив (std::vector, TList или любой другой).

3.Повторить пункт 1, сравнив доступный объем памяти со 100 МБ.

4.Освободить каждый второй из выделенных в пункте 2 блоков при помощи функции VirtualFree().

5.Повторить пункт 1, обратив внимание на объем доступной ВП.

6.Попытаться выделить блок памяти размером ¼ ВП, доступной согласно п. 5. Если пункт выполняется в составе пункта 10, использовать для выделения зарезервированную в пункте 9 область памяти.

7.Освободить оставшиеся выделенные в пункте 2 блоки.

8.Повторить пункт 1, сравнив результаты с полученными в нем ранее.

9.Зарезервировать область памяти того же размера, что и в пункте 6, при помощи функции VirtualAlloc() с флагом

MEM_RESERVE.

10.Повторить пункты 1—6.

11.Определить особенности наблюдавшихся состояний памяти процесса, их различия между собой и объяснить результаты.

Выполнение:

#include <windows.h> #include <cstdlib> #include <cctype> #include <iostream> #include <vector>

#define HUNDRED_MB 100 * 1024 * 1024

//функция нажатия клавиши без эха, возвращает ее код

//аналог нестандартной _getch()

char Getch()

{

static HANDLE hStdOut = GetStdHandle(STD_INPUT_HANDLE); // получаем дескриптор ввода

DWORD mode;

GetConsoleMode(hStdOut, &mode); // получаем текущий режим ввода

// устанавливаем новый режим: отключаем обязательное нажатие <Enter> для ввода и эхо

SetConsoleMode(hStdOut, mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT));

char result = 0; DWORD nread;

ReadConsole(hStdOut, &result, 1, &nread, nullptr); // читаем символ SetConsoleMode(hStdOut, mode); // устанавливаем старый режим return result;

}

// запрос да/нет

bool RequestPausedOutput()

{

std::cout << "Would you like the program to pause at some points,\n" << "allowing you to examine results and/or VMMap? [y/n]\n";

while (true)

{

auto answer = Getch(); // получаем символ ответа

if (tolower(static_cast<unsigned char>(answer)) == 'y') return true; // да

if (tolower(static_cast<unsigned char>(answer)) == 'n') return false; // нет

// неверный ввод. еще раз

std::cout << "Please, press Y or N key!\n";

1

}

}

// пауза

void Pause(bool use_pause = true)

{

if (use_pause)

{

std::cout << "Press any key to continue...\n" << std::endl; Getch(); // пауза до нажатия клавиши

}

}

//отображение общего и доступного объема ВП

//возвращает объем доступной ВП

DWORDLONG PrintMemoryStatus()

{

MEMORYSTATUSEX mem_stat;

mem_stat.dwLength = sizeof(mem_stat); // инициализируем структуру

GlobalMemoryStatusEx(&mem_stat); // получаем информацию о ВП std::cout << "Total VM bytes: " << mem_stat.ullTotalVirtual << '\n'; std::cout << "Available VM bytes: " << mem_stat.ullAvailVirtual << '\n'; return mem_stat.ullAvailVirtual;

}

int main()

{

auto use_pauses = RequestPausedOutput(); // делаем ли паузы

LPVOID reserved = nullptr; // используется при втором проходе заданий. зарезервированная ВП

int pass = 2; // количество проходов п.п. 1-8 while (pass-- > 0)

{

//1. Печатаем начальные значения ВП std::cout << "\t1. In the beginning:\n"; auto initial = PrintMemoryStatus(); std::cout << '\n';

Pause(use_pauses);

//2.

std::vector<LPVOID> mem_allocs; LPVOID p;

// пока удается, выделяем по 100 МБ

while ((p = VirtualAlloc(nullptr, HUNDRED_MB, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE)))

{

mem_allocs.push_back(p); // сохоаняем указатели в вектор

}

// 3. повторяем п. 1

std::cout << "\t3. After full VM utilization:\n"; auto avail = PrintMemoryStatus();

// сравниваем доступную ВП со 100 МБ std::cout << "Residual VM amount is"

<<(avail > HUNDRED_MB ? " > " : " <= ")

<<"100 MB.\n\n";

Pause(use_pauses);

// 4. освобождаем каждый второй блок

2

size_t i = 0;

for (auto& memp : mem_allocs)

{

if (i % 2)

{

VirtualFree(memp, 0, MEM_RELEASE);

memp = nullptr; // обнуляем, чтобы потом дважды не освобождать

}

++i;

}

// 5. повторяем п.1

std::cout << "\t5. After partial VM release:\n"; avail = PrintMemoryStatus();

// еще раз сравниваем доступную ВП со 100 МБ std::cout << "Available VM amount is"

<<(avail > HUNDRED_MB ? " > " : " <= ")

<<"100 MB.\n\n";

Pause(use_pauses);

// 6.

size_t vm_fourth = avail / 4; // 1/4 доступной ВП

std::cout << "\t6.Attempting to allocate " << vm_fourth << " bytes... "; // пытаемся выделить 1/4 доступной ВП

p = VirtualAlloc(reserved, vm_fourth, MEM_COMMIT, PAGE_READWRITE); if (p)

{ // успешно

std::cout << "SUCCEEDED!\n\n"; mem_allocs.push_back(p);

}

else

{ // неудача

std::cout << "FAILED!\n\n";

}

Pause(use_pauses);

//7. освобождаем все что выделено for (auto& memp : mem_allocs)

{

VirtualFree(memp, 0, MEM_RELEASE);

}

mem_allocs.resize(0);

//8. повторяем п.1

std::cout << "\t8. After complete release:\n"; avail = PrintMemoryStatus();

// сравниваем с начальным значением доступной ВП из п.1 std::cout << "Final VM amount is"

<<(avail >= initial ? " >= " : " < ")

<<"initial.\n\n";

Pause(use_pauses);

if (pass > 0)

{// выполняется только на первом проходе, используется для второго (reserved)

//9.

std::cout << "\t9. Reserving " << vm_fourth << " bytes... "; // резервируем память == 1/4 доступной ВП из п.6

reserved = VirtualAlloc(nullptr, vm_fourth, MEM_RESERVE, PAGE_READWRITE); if (reserved)

{ // успех

3

std::cout << "SUCCEEDED!\n\n"; mem_allocs.push_back(reserved);

}

else

{ // неудача

std::cout << "FAILED!\n\n";

}

Pause(use_pauses);

}

}

Pause(); return 0;

}

4

Соседние файлы в папке Windows лаб 1-4