C++ 메모리 구조 및 가상 메모리 조회 - Whitmem
C++ 메모리 구조 및 가상 메모리 조회
C / C++ 언어
2025-07-02 23:50 게시 4fd097d2b05f26adebca

0
0
11
이 페이지는 외부 공간에 무단 복제할 수 없으며 오직 있는 그대로 게시되며 부정확한 내용을 포함할 수 있습니다. 법률이 허용하는 한 가이드 라인에 맞춰 게시 내용을 인용하거나 출처로 표기할 수 있습니다.
This page is not to be distributed to external services; it is provided as is and may contain inaccuracies.
윈도우에서 기본적으로 메모리는 페이지 형태로 관리되며, 각 소프트웨어는 가상 메모리 공간이 할당되어 독립적인 메모리 주소 공간을 보장한다.
따라서 특정 소프트웨어가 어떤 메모리 영역을 사용하는지 조회하는 기능을 WinAPI 에서 제공하는데, 대표적으로 VirtualQuery라는 함수가 있다.
기본적으로 윈도우는 메모리를 페이지 단위로 구별하는데 페이지당 4KB 정도씩 분할하여 페이징한다. 즉 소프트웨어에서 메모리를 2KB 쓸 때 페이지 하나를 할당받아 안에서 2KB 영역을 사용한다.
이 4KB 메모리 영역 하나 하나를 일일이 반환하기에는 관리상 문제도 있기 때문에, 윈도우 운영체제에서 예약된 메모리, 커밋된 메모리, 여유 메모리 주소 부분을 리전 단위로 묶어놓는다.
VirtualQuery 는 리전 단위로 묶여진 메모리 리전을 모두 조회하도록 돕는다.
아무튼 이 함수를 사용하려면 Windows.h 헤더를 포함해야 한다.
#include <Windows.h>
우선 기본적으로 사용 가능한 리전을 제로 베이스부터 반복으로 읽어오며 끝점까지 불러와야 한다.
그러기 위해서 사용 가능한 최소 메모리 주소 위치와 최대 메모리 주소 위치를 가져와야 한다. Windows.h 함수 중에서 GetSystemInfo 라는 함수가 있는데, 이 함수로부터 소프트웨어에 대한 시스템 인포를 가져올 수 있다.
SYSTEM_INFO *systemInfo = new SYSTEM_INFO(); GetSystemInfo(systemInfo);
GetSystemInfo 는 SYSTEM_INFO 구조체를 포인터 변수로 받아 반영해준다.
VOID *maximumAddress = systemInfo->lpMaximumApplicationAddress; VOID *minimumAddress = systemInfo->lpMinimumApplicationAddress;
이 구조체를 포인터로 접근해서 maximumAddress 주소와 minimumAddress 주소를 가져올 수 있다. 즉 상기 minimumAddress 주소를 시작으로 리전을 탐색하되 사이즈를 늘려나가며 리전을 모두 찾아오고, maximumAddress 을 초과하면 리전 탐색을 중단하면 된다.
std::cout << "Min Address : " << minimumAddress << std::endl; std::cout << "Max Address : " << maximumAddress << std::endl;
기본적인 구조체 조회 메커니즘은 아래와 같다.
MEMORY_BASIC_INFORMATION* lpBuffer = new MEMORY_BASIC_INFORMATION(); SIZE_T sizeData = VirtualQuery(nowPosition, lpBuffer, sizeof(MEMORY_BASIC_INFORMATION)); std::cout << "[BASE] " << lpBuffer->BaseAddress << " [SIZE]" << lpBuffer->RegionSize << " [TYPE]" << message << std::endl;
먼저 VirtualQuery 를 요청할 때 첫 인자로는 대상 메모리 시작 위치( 포함 위치 ), lpBuffer 은 MEMORY_BASIC_INFORMATION 의 구조체 포인터를, 그리고 MEMORY_BASIC_INFORMATION 포인터 크기를 기입한다.
그러면 VirtualQuery 는 MEMORY_BASIC_INFORMATION 구조체 안에 각 하나의 리전 정보가 담아서 반환한다.
lpBuffer 에는 BaseAddress, RegionSize와 같은 정보가 포함되는데, 리전 블럭의 정보이다. 리전 블럭은 4KB 의 페이지가 모여서 성질이 같은 페이지를 모아둔 것이다.
lpBuffer 로 포인터 접근을 해보면, 크게 BaseAddress와 State, RegionSize가 존재하는 것을 볼 수 있는데 메모리 리전의 시작 위치, 메모리 리전의 크기, 그리고 해당 메모리 리전의 상태 정보를 포함한다.
nowPosition =(VOID*)((char*)lpBuffer->BaseAddress + lpBuffer->RegionSize);
특히 메모리 상태는 3가지가 존재하는데, 0x1000 는 커밋된 상태, 0x2000는 예약된 상태, 0x10000는 미사용 상태이다. 해당 상태를 구별해서 순회하면서 관여 가능한 메모리 블럭을 모두 조회해보기로 한다.
VOID* nowPosition = (VOID*)minimumAddress; while(true){ MEMORY_BASIC_INFORMATION* lpBuffer = new MEMORY_BASIC_INFORMATION(); SIZE_T sizeData = VirtualQuery(nowPosition, lpBuffer, sizeof(MEMORY_BASIC_INFORMATION)); const char* message=""; switch (lpBuffer->State) { case 0x1000: message = "Memory Commit"; break; case 0x2000: message = "Memory Reserved"; break; case 0x10000: message = "Memory FREE"; break; } std::cout << "[BASE] " << lpBuffer->BaseAddress << " [SIZE]" << lpBuffer->RegionSize << " [TYPE]" << message << std::endl; nowPosition =(VOID*)((char*)lpBuffer->BaseAddress + lpBuffer->RegionSize); if (nowPosition >= maximumAddress) { break; } }
nowPosition 는 발견된 리전의 베이스 위치 + 리전 크기를 더해나가면서 다음 위치 블럭을 찾는다. 즉 다음 영역의 메모리 지점을 nowPosition에 담아 VirtualQuery 를 요청하면 다음 지점에 해당하는 리전 블럭을 찾아 반환해준다. 이러한 작업을 반복하며, 끝점까지 도달하는지 확인하는 것이다.
메모리 영역이 잘 조회되는 것을 볼 수 있다.
댓글 0개
댓글을 작성하는 경우 댓글 처리 방침에 동의하는 것으로 간주됩니다. 댓글을 작성하면 일회용 인증키가 발급되며, 해당 키를 분실하는 경우 댓글을 제거할 수 없습니다. 댓글을 작성하면 사용자 IP가 영구적으로 기록 및 부분 공개됩니다.
확인
Whitmemit 개인 일지 블로그는 개인이 운영하는 정보 공유 공간으로 사용자의 민감한 개인 정보를 직접 요구하거나 요청하지 않습니다. 기본적인 사이트 방문시 처리되는 처리 정보에 대해서는 '사이트 처리 방침'을 참고하십시오. 추가적인 기능의 제공을 위하여 쿠키 정보를 사용하고 있습니다. Whitmemit 에서 처리하는 정보는 식별 용도로 사용되며 기타 글꼴 및 폰트 라이브러리에서 쿠키 정보를 사용할 수 있습니다.
이 자료는 모두 필수 자료로 간주되며, 사이트 이용을 하거나, 탐색하는 경우 동의로 간주합니다.