[뇌를 자극하는 윈도우즈 시스템 프로그래밍] 20장 메모리 관리
가상 메모리 컨트롤
Reserve, Commit, Free
Reserve는 예약 Commit은 할당, Free는 메모리가 할당되지 않은 상태이다.
페이지의 총 개수는 가상 메모리의 전체 크기 / 페이지 하나의 크기 이다.
Commit 상태는 실제로 물리 메모리에 할당이 이루어진 메모리이다.
Free 상태는 메모리 할당이 이루어지지 않은 상태이다.
그리고 Reserve는 가상 메모리 상에서 미리 메모리를 확보해놓는 상태이다.
이 시점에서 해당 페이지는 실제로 메모리가 물리메모리와 매핑되지는 않았지만 다른 용도로 사용되지 않도록 확보해놓는다.
메모리 할당의 시작점과 단위
메모리를 할당할 때는 기본적으로 메모리 할당을 시작할 주소와 할당할 메모리 크기가 필요하다.
일반적으로 페이지는 4KB이기 때문에 메모리 할당시점은 4KB로 나누어 떨어지는 지점일 것이며 할당하는 크기 또한 페이지이다.(단편화를 막기 위해서도 있음)
VirtualAlloc, VirtualFree
VirtualAlloc, VirtualFree는 가상 메모리 상 공간을 다루는 함수이며 Windows에서 malloc free가 내부적으로 이 함수를 사용한다.
https://learn.microsoft.com/ko-kr/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc
VirtualAlloc 함수(memoryapi.h) - Win32 apps
호출 프로세스의 가상 주소 공간에서 페이지 영역의 상태를 예약, 커밋 또는 변경합니다. (VirtualAlloc)
learn.microsoft.com
LPVOID VirtualAlloc(
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
lpAddress: 메모리 시작 주소 lpAddress를 지정한다. 만약 NULL이라면 커널이 적절한 페이지 시작주소를 사용한다.
Reserve -> Commit 상태 변경 시에는 반드시 주소 지정이 필요하다.
dwSize: 할당할 메모리 크기를 지정한다. 기본적으로 4KB의 배수 단위로 설정된다.
flAllocationType: MEM_RESERVE, MEM_COMMIT
flProtect: Page 접근방식에 제한을 둔다. OS차원에서 제한하는 것이다.
https://learn.microsoft.com/ko-kr/windows/win32/api/memoryapi/nf-memoryapi-virtualfree
VirtualFree 함수(memoryapi.h) - Win32 apps
호출 프로세스의 가상 주소 공간 내에서 페이지 영역을 해제, 커밋 해제 또는 해제합니다.
learn.microsoft.com
BOOL VirtualFree(
[in] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD dwFreeType
);
주소와 크기를 지정할 수 있으며
dwFreeTytpe에는 MEM_DECOMMIT, MEM_RELEASE 중 지정할 수 있다.
decommit은 commit->reserve상태 변화이며, release는 free로 만드는 것이다.
Dynamic Array Design
책의 코드 참고
Heap Control
힙 컨트롤은 프로그램 성능 + 구현의 용이성을 위해 이해가 필요하다.
Default Heap, Window System Heap
기본적으로는 malloc, free, new, delete를 사용할 때 힙 영역에 메모리를 할당합니다.
디폴트 힙은 프로세스 힙이라고도 부른다.
기본적으로는 1MB를 RESERVE한다. + 1페이지 커밋

해당 속성에서 힙 예약(reserve), 커밋 크기를 변경할 수 있다.
더 이상 디폴트 힙에 사용할 공간이 없다면 추가적으로 Windows system이 페이지를 확보한다.
Dynamic Heap생성
디폴트 힙 이외에 개발자가 시스템 함수 호출을 해 만드는 힙을 Dynamic Heap이라고 한다.
장점
1. 단편화가 줄어들 수 있다 : 특정 데이터에 대한 힙을 할당하면 메모리 할당에 대한 단편화가 적어진다. 또한 공간 지역성으로 인해 캐시 성능이 좋아질 여지도 있다.
2. 동기화 문제에서 자유로워 성능 향상: 락 동기화가 아닌 Windows 내부의 메모리 동기화의 문제이다. 쓰레드 당 독립된 힙을 할당하는 경우 메모리 할당 해제를 위한 동기화 처리에서 자유로워진다.
Heap 생성, 소멸, 할당
https://learn.microsoft.com/ko-kr/windows/win32/api/heapapi/nf-heapapi-heapcreate
HANDLE HeapCreate(
[in] DWORD flOptions,
[in] SIZE_T dwInitialSize,
[in] SIZE_T dwMaximumSize
);
flOptions: 힙에 특성을 부여한다.
dwInitialSize: 초기 메모리 크기이다. 해당하는 페이지 수만큼 COMMIT 상태가 된다.
dwMaximumSize: 생성되는 힙의 크기이다. 해당하는 페이지 수만큼 RESERVE 상태가 된다.
return값으로 생성된 heap의 핸들이 돌아온다.
https://learn.microsoft.com/ko-kr/windows/win32/api/heapapi/nf-heapapi-heapdestroy
BOOL HeapDestroy(
[in] HANDLE hHeap
);
핸들을 통해 힙을 반환한다.
https://learn.microsoft.com/ko-kr/windows/win32/api/heapapi/nf-heapapi-heapalloc
DECLSPEC_ALLOCATOR LPVOID HeapAlloc(
[in] HANDLE hHeap,
[in] DWORD dwFlags,
[in] SIZE_T dwBytes
);
Heap Alloc을 통해 생성된 힙에 대한 공간을 할당받는다.
return 값으로 할당받은 메모리 블록의 시작주소(포인터)가 return된다.
https://learn.microsoft.com/ko-kr/windows/win32/api/heapapi/nf-heapapi-heapfree
BOOL HeapFree(
[in] HANDLE hHeap,
[in] DWORD dwFlags,
[in] _Frees_ptr_opt_ LPVOID lpMem
);
지정한 힙에 대한 메모리를 해제한다.
시작 주소(할당 받았던)가 인자에 포함된다.
MMF(Memory Mapped File)
MMF는 파일의 일부영역을 Virtual Memory의 일부에 연결시키는 메커니즘이다.
CreateFile을 통해 반환된 파일 핸들이 필요하다.
이후 파일 매핑 오브젝트를 CreateFileMapping 함수 호출을 통해 만든다.
그리고 MapViewOfFile 함수를 통해 가상 메모리에 파일을 연결한다.
이 과정 후에는 OS의 파일캐시와 유저 영역 메모리가 같은 물리 메모리의 페이지를 가리키기 때문에 수정이 반영된다.
COW(Copy On Write) write할 때 copy하라는 의미이다.
만약에 대부분 같은 값의 데이터를 사용하고 매우 드물게 변경한다면 기본적으로는 기본값을 참조하도록 만들고, 변경(수정)이 일어난다면 그 때 새로운 메모리에 복사 후 반영하는 방법이다.