개발/Windows

Windows 캐시와 가상 메모리

bohlee 2025. 5. 22. 00:34

이 글은 윤성우 님의 '뇌를 자극하는 윈도우즈 시스템 프로그래밍'을 참고하여 공부한 내용입니다.


캐시는 프랑스어에서 유래했다고 합니다. 프랑스어로 숨겨진 장소를 뜻하는 Cachette가 영어에서도 사용되며 Cache로 변했다고 하는데요. 그런데 왜 임시 데이터 저장소 용도로 사용되는 메모리를 왜 캐시라고 불렀는지는 잘 모르겠습니다. 문화의 차이일까요?

Cache

캐시 메모리는 CPU가 발전함에 따라 처리 속도가 높아져 주기억장치의 속도 차이로 발생하는 성능 저하를 완화하기 위해 만들어졌습니다. 캐시 메모리는 버스 대역폭 크기, 물리적 거리, SRAM 등의 이유로 주기억장치 보다 속도가 월등하게 빠릅니다. 그래서 CPU와 주기억장치 사이에서 임시 데이터를 저장하여 성능을 완화하는 것입니다.

 

하지만 위 내용만 보았을 때에는 CPU의 처리속도 문제를 CPU-주기억장치에서 캐시-주기억장치 바뀐 것 같습니다. 결국 캐시에 없는 데이터를 주기억장치에서 캐시로 데이터를 가져오면 캐시의 빠른 속도가 이점이 없는 것처럼 보입니다. 그래서 캐시는 자주 사용될 것 같은 데이터를 예상하여 주기억장치에서 데이터를 불러옵니다. 이 것은 지역성, Locality의 원리를 이용한 것으로 지역성의 원리는 크게 2가지로 나뉩니다.

 

for (size_t i = 0; i < arr.size(); ++i)	arr[i] = 0;

 

Temporal Locality

 

첫 번째 시간적 지역성, Temporal Locality은 한번 접근한 데이터는 자주 접근될 가능성이 높다고 판단합니다. 예시로 반복문의 경우 반복 될 때마다 조건문으로 사용되는 데이터에 접근이 이뤄집니다. 그래서 해당 데이터를 계속해서 주기억장치에서 불러오는 것이 아니라 캐시 메모리에 임시 저장하여 접근하는 것입니다.

 

Spatial Locality

 

두 번째 공간적 지역성, Spatial Locality은 데이터에 접근하였을 때 그 주변 데이터도 함께 접근될 가능성이 높다고 판단합니다. 예시로 배열을 생각할 수 있습니다. 배열중 하나의 요소에 접근하였다면 나머지 요소에 접근할 가능성이 높습니다. 그래서 접근한 데이터만 불러오는 것이 아니라 데이터의 주변 데이터까지 포함한 블록 단위로 불러와 저장합니다.

 

위 지역성의 원리를 사용하여 캐시 메모리는 CPU가 접근할 가능성이 높은 데이터를 미리 저장하여 주기억 장치에서 데이터를 불러오는 경우를 줄입니다. 이때 CPU가 필요한 데이터가 캐시 메모리에 있는 경우를 캐시 히트, Cache Hit라 말하며 반대로 접근할 데이터가 캐시 메모리에 없는 경우를 캐시 미스, Cache Miss라고 부릅니다. 

 

Memory Hierarchy

캐시 메모리처럼 주기억장치도 캐시 메모리와 보조기억장치 사이에서 동일한 역할을 합니다. 보조기억장치의 속도는 가장 낮기 때문에 보조기억장치에서 데이터를 불러오는 경우를 줄이기 위해서입니다. 이렇듯 컴퓨터 내 메모리는 속도와 용량에 따른 계층 구조를 갖고 있습니다. 

 

 

메모리의 계층 구조는 주로 피라미드 형태로 표현됩니다. 높은 계층으로 갈수록 메모리는 속도가 빠르고 낮은 계층으로 갈수록 용량이 커져 각 메모리의 성질을 직관적으로 보여주기 때문인 것 같습니다. 상단으로 갈수록 용량이 작아지는 이유는 메모리의 용량당  생산 비용이 급격하게 높아지기 때문입니다.

 

성능을 높이기 위해서는 속도가 낮은 메모리에 접근하는 횟수를 줄여야 합니다. 그래서 각 계층은 낮은 계층에 접근할 경우 해당 데이터를 현재 계층에 저장하여 낮은 계층의 메모리의 접근을 최소화합니다. 캐시처럼 말이죠. 이런 특성 때문에 데이터의 접근은 주로 높은 계층에서 이뤄집니다.

 

캐시도 계층이 나눠져 있습니다. L1 Cache, L2 Cache, L3 Cache로 L1이 속도가 가장 빠르고 용량이 작으며 L3가 속도가 상대적으로 느리고 용량이 큽니다. 그래서 L1에서 캐시 미스가 발생할 경우 L2, L3 순으로 데이터를 탐색합니다. 물론 L3에서도 캐시 미스가 발생할 경우 주기억장치에서 데이터를 탐색하게 됩니다. L3의 경우 다른 캐시와 다른 특성이 있습니다. 바로 CPU 내의 모든 코어가 L3 캐시를 공유한다는 것입니다. 이 점을 이용하여 콘텍스트 스위칭으로 실행 중인 프로세스가  다른 코어에 할당된 경우 주기억장치까지 데이터를 탐색하는 것이 아닌 L3에서 캐시히트를 할 수도 있습니다.

 

Virtual Memory

가상 메모리 시스템은 물리적 메모리 용량보다 더 큰 메모리를 프로세스에게 제공하여 프로세스 실행에 유연성을 높이는 기술입니다. 즉 메모리의 크기는 2GB 밖에 안되지만 프로세스에게 4GB 메모리를 할당해 줄 수 있다는 것입니다. 이것을 가능하게 해주는 것이 페이징, Paging 기법입니다.

 

 

 

Paging

페이징 기법은 물리 메모리를 고정된 크기의 블록인 프레임으로 나누고 이 블록을 가리키는 가상 메모리인 페이지, Page로 관리하는 방식입니다. 페이지는 Page Table을 통해 물리 메모리의 프레임과 맵핑되어 관리되며 CPU가 가상 메모리에 접근하게 되면 MMU를 통해 물리적 주소 변환이 이뤄집니다. MMU, Memory Management Unit은 주소의 변환뿐만 아니라 성능을 위해 버퍼를 가지고 있습니다. 이를 TLB, Translation Lookaside Buffer라고 부릅니다. 이 버퍼는 자주 접근하는 가상 메모리의 페이지의 물리 메모리의 프레임 주소를 가지고 있습니다. 그래서 페이지 테이블 전 TLB를 통해 프레임 주소를 얻을 수 있습니다.

 

여담으로 콘텍스트 스위칭에서 MMU와 TLB 또한 초기화를 진행합니다. 가상 메모리는 각 프로세스에게 독립적으로 존재하기 때문에 동일한 페이지 번호가 다른 프로세스에도 동일하게 사용될 수 있기 때문에 잘못된 주소로 변환되어 데이터 오염의 가능성이 존재하기 때문입니다.

 

다시 돌아와 페이징의 중요한 점은 프로세스의 데이터를 부분적으로 적재한다는 것입니다. 이후 프로세스가 실행되며 데이터가 물리 메모리에 없는 경우 보조기억장치에서 동적으로 페이지 크기의 데이터를 불러오는 것입니다. 만약 물리 메모리의 용량이 부족하다면 이때 특정 페이지들을 보조기억장치에 임시로 저장하여 새로운 페이지들을 적재합니다. 이 과정을 Swap이라 하며 임시 저장되는 보조기억장치 공간을 Swap space라 부릅니다. 이런 식으로 페이지를 스왑 하며 필요한 부분만 데이터를 메모리에 적재하여 사용함으로 실제 메모리 용량보다 더 큰 용량을 프로세스에게 제공할 수 있는 것입니다.