лабораторные Тимофеев / 3316_Кирейкова_Лабораторная2
.pdfМИНОБРНАУКИ РОССИИ
САНКТ-ПЕТЕРБУРГСКИЙ ГОСУДАРСТВЕННЫЙ ЭЛЕКТРОТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ «ЛЭТИ» ИМ. В.И. УЛЬЯНОВА (ЛЕНИНА)
ОТЧЕТ
по Лабораторной работе №2
по дисциплине «Операционные системы»
«Управление памятью»
Выполнила:
Кирейкова С.А.
Группа: №3316
Преподаватель: Тимофеев А. В.
Санкт-Петербург
2025
Цель работы: исследовать механизмы управления виртуальной памятью
Win32.
Задание 2.1. Исследовать виртуальное адресное пространство процесса.
Указания к выполнению.
1. Создайте консольное приложение с меню (каждая выполняемая функция и/или операция должна быть доступна по отдельному пункту меню), которое выполняет:
− получение информации о вычислительной системе (функция
Win32 API – GetSystemInfo);
− определение статуса виртуальной памяти (функция Win32 API – GlobalMemoryStatus);
−определение состояния конкретного участка памяти по заданному с клавиатуры адресу (функция Win32 API – VirtualQuery);
−раздельное резервирование региона и передачу ему физической памяти в автоматическом режиме и в режиме ввода адреса начала региона (функция Win32 API – VirtualAlloc, VirtualFree);
−одновременное резервирование региона и передача ему физической памяти в автоматическом режиме и в режиме ввода адреса начала региона (функция Win32 API – VirtualAlloc, VirtualFree);
−запись данных в ячейки памяти по заданным с клавиатуры
адресам; − установку защиты доступа для заданного (с клавиатуры) региона
памяти и ее проверку (функция Win32 API – VirtualProtect).
2
Демонстрация работы приложения.
Меню:
Получение информации о вычислительной системе:
Определение статуса виртуальной памяти:
Автоматическое резервирование памяти:
Запись данных в ячейки памяти по заданным с клавиатуры адресам:
3
Чтение данных из памяти:
Установка защиты доступа для заданного региона памяти:
Проверка защиты доступа и определение состояния заданного региона памяти:
Код программы
#include <windows.h> #include <iostream> #include <iomanip> #include <string>
4
#include <limits> #include <vector>
using namespace std;
void ShowMenu() {
cout << "Menu:\n"; cout << "0. Exit\n";
cout << "1. Get System Info\n"; cout << "2. Get Memory Status\n"; cout << "3. Memory Region Status\n";
cout << "4. Reserve Memory Region (Manual)\n"; cout << "5. Reserve Memory Region (Automatic)\n"; cout << "6. Write Data to Memory\n";
cout << "7. Read Data from Memory\n"; cout << "8. Set Memory Protection\n"; cout <<
"9. Free Memory Region" << endl; |
|
|
|
} |
|
|
|
void PrintSystemInfo() { |
|
|
|
SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); |
|
|
|
cout << "System Information:\n"; |
|
|
|
cout << " |
Page size: " << sysInfo.dwPageSize << " bytes\n"; cout << " |
Minimum |
|
application address: " |
|
|
|
<< sysInfo.lpMinimumApplicationAddress << "\n"; cout << " |
Maximum |
||
application address: " |
|
|
|
<< sysInfo.lpMaximumApplicationAddress << "\n"; |
|
|
|
cout << " |
Number of processors: " << sysInfo.dwNumberOfProcessors << "\n"; cout |
||
<< "Processor Architecture: "; |
|
|
|
switch (sysInfo.wProcessorArchitecture) { |
|
|
|
case PROCESSOR_ARCHITECTURE_INTEL: |
|
|
|
cout << "x86 (32-bit)" << endl; break; |
|
|
|
case PROCESSOR_ARCHITECTURE_AMD64: |
|
|
|
cout << "x64 (64-bit)" << endl; break; |
|
|
|
case PROCESSOR_ARCHITECTURE_ARM: |
|
|
|
cout << "ARM" << endl; |
|
|
|
break; default: |
|
|
|
cout << "Unknown" << endl; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
void PrintMemoryStatus() { |
|
|
|
MEMORYSTATUSEX memStatus; |
|
|
|
memStatus.dwLength = sizeof(memStatus); GlobalMemoryStatusEx(&memStatus); |
|
||
cout << "Memory Status:\n"; |
|
|
|
cout << " |
Memory in use: " << memStatus.dwMemoryLoad << "%\n"; |
|
|
cout << " |
Total physical memory: " << memStatus.ullTotalPhys / 1024 / 1024 << " |
||
MB\n"; |
|
|
|
cout << " |
Available physical memory: " << memStatus.ullAvailPhys / 1024 / 1024 |
||
<< " MB\n"; |
|
|
|
cout << " |
Total virtual memory: " << memStatus.ullTotalVirtual / 1024 / 1024 << |
||
" MB\n"; |
|
|
|
cout << " |
Available virtual memory: " << memStatus.ullAvailVirtual / 1024 / 1024 |
||
<< " MB\n"; |
|
|
|
} |
|
|
|
string GetMemoryState(DWORD state) { switch (state) {
case MEM_COMMIT: return "MEM_COMMIT"; case MEM_RESERVE: return "MEM_RESERVE"; case MEM_FREE: return "MEM_FREE"; default: return "Unknown";
}
}
5
}
cout << "Memory region allocated at address: " << lpMemory << endl;
}
void ReadFromMemory() {
UINT_PTR address; HANDLE process; SIZE_T bytesread; const int buffersize = 256; char buffer[buffersize]; process = GetCurrentProcess();
cout << "Enter memory address to read from: "; cin >> hex >> address; if (cin.fail()) {
cerr << "Invalid memory address!" << endl; return;
}
if (ReadProcessMemory(process, (LPCVOID)address, buffer, buffersize, &bytesread) &&
bytesread > 0) {
cout << "Data has been successfully read from memory " << string(buffer, bytesread) << endl;
}
else {
cerr << "Failed to read data from memory! " << endl;
}
CloseHandle(process);
}
void WriteToMemory() {
UINT_PTR address; string data; HANDLE process;
cout << "Enter memory address for writing data: "; cin >> hex >> address; if (cin.fail()) {
cerr << "Invalid memory address!" << endl; return;
}
cout << "Enter data for writing: "; cin.ignore(); getline(cin, data);
process = GetCurrentProcess(); auto lpAddress = (LPVOID)address; SIZE_T byteswritten;
if (WriteProcessMemory(process, lpAddress, data.c_str(), data.size(), &byteswritten) && byteswritten == data.size()) {
cout << "Data has been successfully written to memory " << endl;
}
else {
cerr << "Error while writing data to memory! " << endl;
}
CloseHandle(process);
}
DWORD ChooseMemoryProtection() { int choice;
cout << "Choose memory protection:" << endl; cout << "1. PAGE_READONLY" << endl; cout << "2. PAGE_READWRITE" << endl;
cout << "3. PAGE_EXECUTE" << endl; cout << "4. PAGE_EXECUTE_READ" << endl;
cout << "5. PAGE_EXECUTE_READWRITE" << endl; cout << "6. PAGE_NOACCESS" << endl; cout << "Enter your choice: "; cin >> choice;
switch (choice) {
case 1: return PAGE_READONLY; case 2: return PAGE_READWRITE; case 3: return PAGE_EXECUTE;
case 4: return PAGE_EXECUTE_READ;
case 5: return PAGE_EXECUTE_READWRITE; case 6: return PAGE_NOACCESS; default:
7
cerr << "Invalid choice! Defaulting to PAGE_READWRITE." << endl; return PAGE_READWRITE;
}
}
void SetMemoryProtection() { UINT_PTR address;
DWORD protection = ChooseMemoryProtection(); DWORD oldProtect;
cout << "Enter memory address (in hexadecimal): "; cin >> hex >> address; if (cin.fail()) {
cerr << "Invalid memory address!" << endl; return;
}
SIZE_T size;
cout << "Enter size of the memory region (in bytes): "; cin >> dec >> size; if (cin.fail()) {
cerr << "Invalid size!" << endl; return;
}
LPVOID lpAddress = reinterpret_cast<LPVOID>(address);
if (VirtualProtect(lpAddress, size, protection, &oldProtect)) { cout << "Memory protection set successfully!" << endl;
cout << "Protection set to: " << hex << protection << "\n";
}
else {
cerr << "Failed to set memory protection.\n";
}
}
void FreeMemory() { LPVOID lpAddress; SIZE_T dwSize;
cout << "Enter memory address to free: "; cin >> lpAddress; cout << "Enter size to free: "; cin >> dwSize; VirtualFree(lpAddress, dwSize, MEM_DECOMMIT);
cout<< "Memory region freed " <<endl;
VirtualFree(lpAddress, dwSize, MEM_RELEASE); cout << "Memory region freed " <<
endl;
}
int main() {
int choice;
void* address = nullptr; SIZE_T size = 0; string data;
while (true) { ShowMenu();
cout << "Enter your choice: "; cin >> choice;
switch (choice) { case 1:
PrintSystemInfo(); break; case 2: PrintMemoryStatus(); break; case 3:
MemoryRegionStatus(); break; case 4:
ReserveManual(); break; case 5:
8
ReserveAutomatic(); break; case 6:
WriteToMemory(); break;
case 7: ReadFromMemory();
break; case 8: SetMemoryProtection();
break; case 9: FreeMemory();
break; case 10: return 0; default:
cerr << "Invalid choice. Please try again.\n"; break;
}
}
return 0;
}
Выводы по первой части
В ходе выполнения первой части были изучены принципы управления виртуальной памятью с помощью функций библиотеки Win32 API.
Приложение дает возможность пользователю резервировать и обращаться к определенному участку виртуальной памяти, размер которого можно также вводить вручную, записывать в данный регион данные, читать их и очищать.
Программа позволяет пользователю получать информацию о системе,
получать информацию о конкретном интересующем пользователя участке памяти, устанавливать для него новые атрибуты защиты. Приложение осуществляет взаимодействие с виртуальной памятью компьютера, упрощая работу пользователю.
9
Задание 2.2. Копирование файла с помощью операций перекрывающегося ввода-вывода.
Задание на проецируемый файлы. Два приложения – клиент и сервер.
Сервер создает файл на диске и проецирует его в память, далее записывает информацию и ждет, пока клиент не прочтет, затем отменяет проецирование и удаляет файл.
Клиент открывает файл, проецирует и ждет доступности чтения, затем читает и выводит результат, в завершении работы отменяет проецирование.
Сделать меню в каждой программе:
пункты меню Сервера – «выполнить проецирование», «записать данные», «завершить работу»;
пункты меню Клиента – «выполнить проецирование»,«прочитать данные», «завершить работу».
Проецируемые файлы позволяют резервировать регион адресного пространства и передавать ему физическую память, которая не выделяется из страничного файла, а берется из файла, уже находящегося на диске.
Как только файл спроецирован в память, к нему можно обращаться так, будто он целиком в нее загружен.
Когда несколько процессов используют mmap() для отображения одного и того же файла, они могут работать с общей памятью:
Ядро отображает виртуальные адреса разных процессов на одни и те же физические страницы памяти (таблицы страниц каждого процесса содержат записи, указывающие на одинаковые физические страницы).
Если процессы используют флаг MAP_SHARED при вызове mmap() для отображения общего файла, то оба процесса будут работать с одними и теми же физическими страницами памяти (изменения, сделанные одним процессом в отображённой памяти, автоматически видны другому процессу, работающему с тем же файлом).Данный флаг влияет на взаимодействие между процессорам, совместное использованием ими памяти, синхронизацию изменений с файлом на диске.
Если процессы используют общую память, ядро обеспечивает согласованность данных через механизмы синхронизации (например, с помощью msync() для принудительной записи изменений на диск).
Процесс проецирования:
10
