ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • VirtualAlloc()의 메모리 할당에 대해
    개발/C·C++ 2024. 10. 12. 20:39

    VirtualAlloc()이 과거에는(?) 메모리 할당이 64KB 단위로 이루어졌던 것 같다.

    과거의 데이터로 학습한 Perplexity의 대답도 그렇고

    윈도우 시스템 프로그래밍 관련한 강의(최근에 제작된 것)에서도 관련한 내용으로 학습했다.

     

    개인적으로 정리를 하던 와중에 정말 VirtualAlloc()으로 메모리 요청을 했을 때

    정말 최소 할당 값이 64KB이 궁금했고 테스트를 해봤다.

    현대적인 윈도우는 메모리 풀링을 하지 않고 new / delete만 써도 메모리 최적화가 잘 된다는 실무자 전언을 들었다.

    메모리 풀링을 하는 몇 가지 이유는 작은 메모리 공간을 요청에 대한 오버헤드가 큰 것과 작은 메모리 공간에 대한 잦은 할당과 반복이 메모리 단편화를 만들 수 있기 때문이다.

     

    이 이야기를 들어서일까 VirtualAlloc()이 반환하는 메모리의 최소 할당 단위가 64KB이란 사실이

    점점 석연치 않은 느낌이 들었던 것 같다.

    일단 여전히 메모리 정렬 단위(granularity)는 64KB가 맞다. 64비트 프로세서 기준이고 x86, x64 둘 다 동일하다.

    	SYSTEM_INFO info;
    	::GetSystemInfo(&info);
    	cout << info.dwAllocationGranularity << endl;

     

    검색을 해보니 VirtualQuery()를 이용하면 할당된 크기를 알 수 있다고 해서 다음과 같이 해봤다.

    	void* memory = VirtualAlloc(nullptr, 4, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    	MEMORY_BASIC_INFORMATION mbi;
    	VirtualQuery(memory, &mbi, sizeof mbi);
    	size_t actual_size = mbi.RegionSize;
    	cout << actual_size << endl;

     

    4096. 최소 할당 단위가 페이지 크기로 바뀐 걸까, 아니면 64KB를 할당해놓고 첫 번째 페이지만 읽은걸까? 사실 후자일 가능성은 적어 보인다. 그럼 페이지 단위로 해서 64KB를 훑어보자.

    	if ((int)memory % 64 != 0)
    	{
    		cout << "Not 64KB granularity" << endl;
    	}
    	for (int i = 0; i < 16; ++i)
    	{
    		char* ptr = (char*)memory;
    		*(ptr + i * 4096) = 1;		
    		cout << "access success at i:" << i << endl;
    		cout << "access success at offset:" << i * 4096 << endl;
    	}

    위 코드를 수행하면 두 번째 반복에서 바로 메모리 접근 오류가 발생한다. VirtualAlloc() 함수가 만들어주는 메모리 공간의 최소 값이 4KB일 가능성이 높아졌다. 그럼 32KB만 요청해서 같은 테스트를 해보자. 이번엔 정밀한 테스트를 위해 페이지 단위가 아니라 1바이트 단위로 수행한다.

     

    	void* memory = VirtualAlloc(nullptr, 32768, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    	MEMORY_BASIC_INFORMATION mbi;
    	VirtualQuery(memory, &mbi, sizeof mbi);	
    	size_t actual_size = mbi.RegionSize;
    	cout << actual_size << endl;
    
    	if ((int)memory % 64 != 0)
    	{
    		cout << "Not 64KB granularity" << endl;
    	}
    	for (int i = 0; i < 32768; ++i)
    	{
    		char* ptr = (char*)memory;
    		*(ptr + i) = 1;		
    	}

     

    반복문의 탈출 조건을 32769로 하면 메모리 위반 오류가 난다. 정확하게 요청 값 32KB만큼 할당된 것이다. 메모리 정렬은 64단위가 유지된다. 4097을 요청하면 8192KB가 할당되는 걸 확인할 수 있다. 즉 최소 할당 값은 페이지와 같은 4KB이며 할당 단위도 4KB임을 알 수 있다.

    댓글

Designed by Tistory.