Windows.h

VirtualAlloc

노력하는우리 2021. 3. 14. 01:15

new를 항경우 내부에서 malloc을 호출하고 malloc 안에서 다시 heapAlloc이 호출 되며 그 마지막에 있는 것이 VirtualAlloc이다.

이 VirtaulAlloc은 Window.h안에 포함 되어 있으며

유저가 사용할 수도 있다.

MSDN에 있는 내용을 그대로 가져왔다.

우섯 첫번째 인자인 lpAddress는 메모리 시작 지점이다. 우리가 처음 저 함수를 호출 할 때는 NULL을 넣어서 호출 한다.

사실상 Reserve된 메모리를 Commit으로 바꿀때만 쓰이는것같다.(예제를 아무리 찾아봐도 첫호출에 주소를 넣는 경우가 없네요)

 

두번째는 dwSize 할당 받을 크기를 받는 인자이다. 우리가 어떤 숫자를 넣던 4KB단위로 끊어서 처리 해준다.

그 이유는 윈도우가 가상메모리를 4KB인 페이지로 관리하기 떄문이다.

 

세번째는 COMMIT을 할 것인지 RESERVE를 할 것인지 이다. COMMIT이 된다는건 실제로 물리메모리와 이어졌다는 것이고 RESERVE는 공간을 미리 잡아 놓은것이다 그렇다면 Reserve는 왜 필요한 것일까.

우리는 배열처럼 공간의 연속성을 활용한 데이터가 있을 때 이 연속성이 끊기지 않는 것이 중요하다. 만약 COMMIT만 해놓고 다른 곳에서 VirtualAlloc이 호출 되면 그 연속성이 끊어지게 된다.

하지만 예를들어 1000의 공간을 Reserve해놓고 앞의 0~100의 공간만 commit 해놓고 쓰다가 다시 100~200의 공간을 Commit 하게되면 0~200의 공간은 연속적으로 이어 지게된다 (물론 물리 메모리가 아닌 가상메모리이다)

MEM_COMMIT, MEM_RESERVE

 

 

네번째 인는 읽기전용인지 접근불가 인지 읽기쓰기를 다 허용하는지를 받는 인자이다.

PAGE_NOACCESS, PAGE_READWRITE, PAGE_READONLY

 

그런데 이 녀석은 PAGE 기준인 4KB단위로 commit과 reserve를 하나 실제로 우리에게 반환하는 주소는 64KB 단위로 끊어져 있다. 

그 것을 AllocationGranularity라고 하는데 왜 이녀석 단위로 끊어내는지 정확한 이유는 아직 찾지 못했다 (찾으면 수정하겠습니다.. 아시는 분 좀 알려주세요)

 

자 그러면 실제로 VirtaullAlloc이 페이지단위로 할당하는 지 AllocationGranularity 기준으로 뱉어내는 지를 알아보자.

우선 시스템의 정보를 볼 수 있는 함수를 통해 Page 크기와 Granularity를 알아보자.

결과는

 

우리가 알고 있던데로 페이지 사이즈는 4KB

Granularity는 64KB이다

 

그럼 이제 VirtualAlloc을 통해 실제로 메모리를 할당 받아보자

1바이트를 사이즈로 넣고 할당 받아 보겠다.

중단점 걸고 실행

0x009e0000 번지부터 주소가 할당되었다 실제로 확인하러가보면

 

0x009e0000 부터 1바이트만 커밋된 것이 아닌 0x009e1000까지인 4KB가 커밋 되었다

 

VirtualAlloc을 1바이트씩 연속으로 두번 할당 받으면 어떻게 될까? 4KB간격 주소가 2개 할당 될까?

결과는

0x1000(4KB)이 아닌 0x10000(64KB)간격으로 할당 되어 버렸다.

이것이 AllocationGrnularity이다

그래서 VirtualAlloc을 적절히 사용하지 못하면 엄청난 메모리공간을 낭비하게된다.

 

그러면 64KB단위가아닌 4KB단위로 연속적 할당을 받고싶은 경우라면 어떻게 해야할까?

우선 Reserve로 충분한 공간을 예약한뒤 페이지 단위로 순차적인 Commit을하면 된다.

여기서 4096이 아닌 1024를 해준 이유는 int형이라서 이다