※ 아래는 윤성우 뇌를 자극하는 윈도우즈 프로그래밍 한빛미디어(주) 2022년
Chapter20(p.673 ~ 714)를 읽고 정리한 내용입니다.
가상 메모리 크기 / 페이지 하나당 크기 = 페이지의 개수
-> 페이지 개수는 가상 메모리 크기에 비례
-> 모든 페이지는 Reserved, Commit, Free 중 하나의 상태를 가짐
해당 페이지가 물리 메모리(램과 하드 디스크를 모두 포함한 메모리)에 할당된 상태
물리 메모리 할당이 이루어지지 않은 페이지
Commit과 Free의 중간 상태
-> 다른 메모리 할당 함수에 의해 해당 번지가 할당되지 못하도록 선언 가능
-> 물리 메모리에 할당되지는 않음 (말 그대로 예약 상태)
페이지 단위로 메모리를 할당하기에 앞서 알아야 하는 정보
(1) 메모리 할당의 시작 주소
(2) 할당할 메모리의 크기
가상 메모리 시스템은 페이지 단위로 관리된다.
-> 페이지의 중간 위치부터 할당을 시작할 수 없으며, 페이지 크기의 배수 단위로 할당을 해야 한다.
메모리 할당의 시작 주소가 될 수 있는 기본 단위를 가리쳐 'Allocation Granularity Boundary'라 한다.
LPVOID VirtualAlloc(LPVOID lpAddress, // 예약 및 할당하고자 하는 메모리의 시작 주소
// 일반적으로 NULL 전달
// Reserve 상태에 있는 페이지를 Commit 상태로
// 변경할 때에는 해당 페이지의 시작 주소를 지정해야 함
SIZE_T dwSize, // 할당하고자 하는 메모리의 크기를 바이트 단위로 지정
DWORD flAllocationType, // 메모리 할당의 타입을 결정
// MEM_RESERVE -> Reserve 상태
// MEM_COMMIT -> Commit 상태
DWORD flprotect); // 페이지별 접근방식에 제한을 두는 용도
// PAGE_NOACCESS -> Reserve 상태일 때 접근을 허용하지 않음
// PAGE_READWRITE -> Commit 상태로 변경할 때 읽기 쓰기 모두 허용
BOOL VirtualFree(LPVOID lpAddress, // 해제할 메모리 공간의 시작 주소를 지정
SIZE_T dwSize, // 해제할 메모리 크기를 바이트 단위로 지정
DWORD dwFreeType); // MEM_DECOMMIT과 MEM_RELEASE 중 하나 지정
// MEM_RELEASE를 지정할 경우 해당 페이지는 Free 상태가 된다.
// 물리적 메로리가 할당되어 있다면 해당 메모리는 반환된다.
// 주의할 사항은 MEM_RELEASE 전달 시 두 번째 전달인자 dwSize는 반드시 0이어야 하고,
// lpAddress의 값은 VirtualAlloc 함수 호출을 통해 예약된 메모리의 시작 번지로 되어야 한다.
일반적인 배열처럼 한순간에 배열 크기만큼 물리 메모리가 할당되는 것이 아니라 사용양의 증가에 따라
물리 메모리에 할당되는 배열
C++을 사용할 경우 new와 delete 연산자를 사용해서 힙 영역에 메모리를 할당한다.
프로세스를 생성할 때 더불어 생성되는 힙을 디폴트 힙이라 한다.
(정확히 말하면 1MB 크기의 디폴트 힙 영역에 메모리를 할당하게 됨, 프로세스 힙이라고도 함)
Windows 시스템 함수 호출을 통해서 생성되는 힙
| # | Dynamic Heap의 장점 | 설명 |
|---|---|---|
| 1 | 메모리 단편화의 최소화에 따른 성능 향상 | 디폴트 힙을 활용할 경우 프로그램 실행과정에서 무작위 메모리 할당 및 그에 따른 힙 크기의 증가에 의해 메모리 단편화가 심하게 발생한다. 단편화가 심하다는 것은 프로그램의 로컬리티 특성이 낮아진다는 것을 의미하며, 이는 성능에 많은 영향을 미친다. |
| 2 | 동기화 문제에서 자유로워짐으로 인한 성능 향상 | 같은 주소 번지에 둘 이상의 쓰레드가 동시에 할당 및 해제하는 상황이 발생할 경우 메모리 오류가 발생한다. 때문에 디폴트 프로세스 힙은 쓰레드가 메모리를 할당하려고 하는 경우 내부적으로 동기화 처리를 하고 있다. 그런데 하나의 쓰레드당 독립된 하나의 힙을 할당할 경우 동기화 처리를 할 필요가 없고 이것으로 인한 성능 향상을 기대할 수 있게 된다. |
HANDLE HeapCreate(DWORD flOptions, // 생성되는 힙의 특성을 부여하는 데 사용
// 0을 전달할 경우 가장 일반적인 힙 생성
SIZE_T dwInitialSize, // 3번째 인자에서 지정한 메모리 중 초기에 할당할 물리 메모리 크기 지정
// 여기서 지정한 크기에 해당하는 페이지 수만큼 Commit 상태가 됨
SIZE_T dwMaximumSize); // 생성되는 힙의 크기 결정
// 0을 전달하면 힙은 증가 가능한 메모리가 됨
BOOL HeapDestroy(HANDLE hHeap); // 반환하고자 하는 힙의 핸들을 인자로 전달
LPVOID HeapAlloc(HANDLE hHEAP, // 메모리 할당이 이뤄질 힙의 핸들 지정
DWORD dwFlags,
SIZE_T dwBytes); // 할당하고자 하는 메모리의 크기 지정
BOOL HeapFree(HANDLE hHeap, // 해제할 메모리를 담고 있는 힙 지정
DWORD dwFlags, // HEAP_NO_SERIALIZE가 인자로 올 수 있다.
// HeapCreate 함수 호출 과정에서 이미 HEAP_NO_SERIALIZE를
// 전달하였다면 이 전달인자를 통해서 중복 지정할 필요 없다.
LPVOID lpMem); // 해제할 메모리의 시작 주소를 지정한다.
파일의 일부 영역을 가상 메모리 일부에 연결시키는 메커니즘

(1) 프로그래밍하기 편리하다
-> MMF를 사용하면 메모리상에 저장된 데이터를 조작하는 방식으로 파일 내 데이터를 조작할 수 있다.
(2) 성능이 향상된다
-> 메모리는 중간에서 파일 데이터의 캐쉬 역할을 한다고 이해하면 된다.
-> 캐쉬가 존재하므로 직접 파일에 접근하는 것보다 효율적인 접근이 이뤄진다.
write 할 때 copy 하라
-> 데이터를 쓸 때 복사하는 기술
-> CreateFileMapping 함수의 세 번째 전달 인자로 PAGE_WRITECOPY를 지정하면 COW 기반으로 동작함