포스트

VirtualAlloc (가상 메모리 할당 및 예약)

virualAlloc이란, C++에서 프로그램 실행 시간 동안 메모리를 할당 받는 동적 할당 키워드 중 Windows 운영체제에서 가상 메모리를 할당하고 관리하는 함수입니다.

가상 메모리 공간은 물리 메모리보다 훨씬 크며, 운영체제가 관리합니다.

동적 할당 키워드 (new, malloc, calloc, realloc)


예약과 할당

VirtualAlloc 은 다른 동적 할당 키워드들과 다르게 메모리 공간에 대한 예약이 가능하고, 예약 상태엑세스 권한 지정이 가능합니다.

이때, 예약 및 할당의 경우 시스템의 페이지 크기의 정수 배인 주소에 정렬된 메모리를 할당합니다. (페이지 크기는 x64 및 x86에서 4,096 바이트(4 KB)입니다.)

가상 메모리란, 보통 보조 기억 장치에 저장되기 때문에 이 페이지 단위를 사용합니다.

HDD의 섹터 크기는 일반적으로 512 ~ 4,096 바이트이며 CD-ROM의 경우 2,048 바이트이기 때문에, 이 섹터의 크기와 가상 메모리의 크기를 일치시키기 위해서 페이지의 크기가 4,096 바이트인 것입니다. (섹터 크기가 페이지 크기보다 큰 경우는 드뭅니다.)

다만, 이렇게 예약된 4 KB의 공간은 연속된 메모리 공간으로 예약되기 때문에 다른 데이터가 중간에 쓸 수 없게 만듭니다.

물론, 4 KB 보다 큰 메모리 공간을 필요로 한다면 이런 공간의 낭비가 다소 존재하더라도 연속된 공간에 예약하는 것이 더 좋습니다.

예약과 권한 관련 플래그

  • 메모리 예약 플래그:
    • MEM_COMMIT: 물리 메모리를 할당하고 페이지를 액세스할 수 있도록 합니다. 이후, 페이지가 물리 메모리에 매핑되며, 초기 값은 0이 됩니다.
    • MEM_RESERVE: 가상 주소 공간을 예약하지만 물리 메모리를 할당하지 않습니다.
      따라서, MEM_RESERVE만 사용하면 해당 페이지에 액세스할 수 없으며, MEM_COMMIT을 사용해야 페이지에 액세스할 수 있습니다.
  • 엑세스 권한:
    • PAGE_NOACCESS: 페이지에 대한 모든 액세스를 차단합니다.
    • PAGE_READWRITE: 페이지에 대한 읽기 및 쓰기 액세스를 허용합니다.
    • PAGE_READONLY: 페이지에 대한 읽기 액세스만 허용합니다.

VirtualAlloc 함수

VirtualAlloc 함수는 다음과 같이 사용합니다.

  1. lpAddress: 메모리 공간을 예약하고 싶다면 메모리 시작 주소NULL로 두고 메모리 시작 지점을 운영체제에서 받아와야 합니다. (이미 예약된 공간을 접근하기 위해 COMMIT으로 사용하려면, 이때 받은 주소를 이 LPVOID 에 메모리 시작 주소를 넣어주면 됩니다.)
  2. dwSize: 예약 공간은 4KB 단위의 크기로 할당합니다.
  3. flAllocationType: 메모리 예약 플래그를 사용해 메모리를 할당 받습니다. 메모리 시작 주소를 넣지 않았더라도 할당 받고 바로 사용하려면 MEM_COMMIT 을 사용할 수 있습니다.
  4. flProtect: 엑세스 권한을 설정합니다.
  5. 메모리 할당 및 예약을 성공하면 할당된 페이지 영역의 시작 주소가 반환됩니다. 함수가 실패하면 NULL이 반환됩니다.
1
2
3
4
5
6
LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,
  [in]           DWORD  flProtect
);

페이지(Page)란?

페이지는 컴퓨터의 물리적 메모리를 일정한 크기의 블록으로 나눈 것을 말합니다.

일반적으로 페이지의 크기는 4KB입니다.

페이지의 크기

페이지의 크기가 4 KB인 이유에는 여러가지가 있습니다만, 현재는 하드웨어와의 호환성 때문인 것으로 알려져 있습니다.

1) 하드웨어와의 호환성

4KB는 하드 드라이브의 섹터 크기와 일치하는 경우가 많습니다.

예를 들어, HDD와 CD-ROM은 섹터라는 단위로 데이터를 저장하며, 이 섹터의 크기가 일반적으로 512바이트나 4KB가 될 수 있습니다.

SSD도 섹터를 사용하며, 섹터 크기는 기술과 제품에 따라 다를 수 있지만 일반적으로 4KB 크기를 가집니다.

따라서, 페이지 크기와 섹터 크기가 일치하게 하여 입출력 작업을 좀 더 효율적으로 하게 하기 위함입니다.

2) 효율적인 메모리 관리

초기 컴퓨터 시스템에서 4KB는 데이터를 관리하기 충분한 크기로 여겨졌고, 이 크기가 현재까지 계속 사용되고 있습니다.

  • 너무 작은 페이지: 페이지 크기가 너무 작으면 페이지 테이블이 커지고, 페이지 관리 오버헤드가 증가합니다.
  • 너무 큰 페이지: 페이지 크기가 너무 크면 메모리 낭비가 발생할 수 있습니다. 예를 들어, 프로그램이 3KB의 메모리만 필요한데 페이지 크기가 5KB라면 2KB의 메모리가 낭비됩니다.

4KB는 초기 컴퓨터 시스템에서 이 두 가지 문제 사이에서 균형을 찾은 값으로 생각됩니다.

페이지를 사용하는 이유

1) 페이지와 가상 메모리

페이지는 가상 메모리 시스템에서 중요한 역할을 합니다.

가상 메모리물리적 메모리보다 큰 메모리 공간을 프로그램에 제공하는 기술입니다. 주로 보조 기억 장치를 사용합니다.

프로그램이 가상 메모리 주소를 사용하면, 이 가상 메모리 주소는 실제 물리적 메모리 주소로 변환되어야 합니다.

페이지는 이 변환 과정에서 중요한 역할을 하며, 가상 메모리 주소를 물리적 메모리 주소로 매핑할 때, 페이지 테이블을 사용합니다.

2) 메모리 단편화와 메모리의 효율적 관리

페이지를 사용하면 메모리를 효율적으로 관리할 수 있습니다.

다른 동적 메모리 할당시 발생하는(연속된 메모리 공간에 필요 공간를 할당하고 해제하는 과정에서 발생하는) 메모리 단편화극복할 수 있습니다.

위에서 가상 메모리는 페이지로 관리되고, 페이지 테이블을 통해 물리적 메모리 주소와 매핑된다고 설명 드렸습니다.

페이징_페이지 테이블.png 가상 메모리 주소를 실제 물리 메모리 주소로 매핑

만약, 연속된 할당으로 물리 메모리에 할당하게 된다면, 0번 메모리 공간이나 3번 메모리 공간에 해당 공간보다 더 큰 메모리를 할당할 수 없게 될 것입니다.

이것이 메모리 단편화(외부 메모리 단편화)입니다.

하지만, 이를 페이지로 관리하게 된다면 이 공간을 최대한 활용할 수 있게 됩니다.

페이징_단편화 해결.png

이런식으로 프로그램이 실행되면서 필요한 메모리를 페이지 단위로 할당하고 해제함으로써 메모리의 낭비를 줄이고 관리를 용이하게 합니다.

페이지 폴트

프로그램이 접근하려는 페이지가 물리적 메모리에 없을 때 발생하는 현상을 페이지 폴트라고 합니다.

이때, 운영체제는 해당 페이지를 보조 기억 장치에서 물리 메모리로 로드하여 프로그램에 필요한 데이터를 제공합니다.

요약:

  • 페이지는 메모리를 일정한 크기의 블록으로 나눈 것입니다.
  • 페이지는 메모리 관리를 효율적으로 하기 위해 사용됩니다.
  • 페이지로 인해 메모리 단편화를 극복할 수 있습니다.
  • 가상 메모리 시스템에서 페이지는 물리적 메모리와 가상 메모리 사이의 매핑을 관리합니다.

정리

  • Windows 운영체제에서 가상 메모리(Virtual Memory)에 공간을 할당하고 관리합니다.
  • 페이지 단위로 메모리를 할당할 수 있으며, 특정 주소에 메모리를 할당할 수 있습니다. (보통 예약된 페이지가 아니라면 NULL로 넘겨 비어있는 충분한 공간을 할당 받습니다.)
  • 연속적으로 메모리를 할당하고 해제하는 과정에서 발생하는 메모리 단편화를 극복할 수 있습니다.
  • 대용량의 메모리가 필요한 경우 유용합니다.
  • 메모리에 대한 예약이 가능하고, 예약 상태 및 엑세스 권한 지정이 가능합니다.
  • 메모리 예약 플래그는 다음과 같습니다.
    • MEM_COMMIT: 물리 메모리를 할당하고 페이지가 물리 메모리에 매핑되며, 초기 값은 0이 됩니다.
    • MEM_RESERVE: 가상 주소 공간을 예약하지만 물리 메모리를 할당하지 않습니다. 따라서, MEM_RESERVE만 사용하면 해당 페이지에 액세스할 수 없으며, MEM_COMMIT을 사용해야 페이지에 액세스할 수 있습니다.
  • 엑세스 권한은 다음과 같습니다.
    • PAGE_NOACCESS: 페이지에 대한 모든 액세스를 차단합니다.
    • PAGE_READWRITE: 페이지에 대한 읽기 및 쓰기 액세스를 허용합니다.
    • PAGE_READONLY: 페이지에 대한 읽기 액세스만 허용합니다.
  • 메모리 해제는 virtualfree
1
VirtualAlloc(NULL(메모리 시작 지점), 4KB 단위의 크기, COMMIT 또는 RESERVE, 엑세스 권한)
1
2
3
4
5
6
7
#include <windows.h>

int main() {
    LPVOID pMemory = VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE); // 4096 바이트 크기의 가상 메모리 할당
    //...
    VirtualFree(pMemory, 0, MEM_RELEASE); // 메모리 해제
}

참고

동적 할당 키워드 (new, malloc, calloc, realloc, virtualAlloc)

이 기사는 저작권자의 CC BY-NC-ND 4.0 라이센스를 따릅니다.