CPU가 데이터를 얼마나 빨리 가져오기 위해 메모리를 어떻게 관리하느냐

컴퓨터에서 CPU는 계산을 하는 역할을 하고, 계산에 필요한 명령이나 데이터는 메모리에서 가져온다. 그런데 메모리는 단계가 나뉘어 있다. CPU 바로 옆에 있는 아주 빠른 메모리가 캐시 메모리이고, 그보다 느리지만 큰 공간이 주기억장치(RAM)다. CPU는 항상 캐시 메모리부터 확인하고, 거기에 필요한 데이터가 없으면 RAM까지 가서 데이터를 가져온다. 이때 “CPU가 필요로 하는 데이터가 캐시에 잘 있도록 유지하는 방법 전체”를 캐시 메모리 관리라고 부른다.

먼저 캐시 메모리 인출 방식은 “데이터를 언제 캐시에 올려두느냐”에 대한 이야기다. Demand Fetch는 정말 필요해졌을 때만 캐시에 올리는 방식이다. CPU가 데이터를 달라고 했는데 캐시에 없으면 그때 RAM에서 가져온다. 이해하기 쉽지만, 그 순간에는 기다림이 발생한다. Pre-Fetch는 CPU가 곧 필요로 할 것 같은 데이터를 미리 예측해서 캐시에 올려두는 방식이다. 미리 준비해 두기 때문에 속도는 빨라질 수 있지만, 예측이 틀리면 쓸모없는 데이터를 올려두는 낭비가 생길 수 있다.

다음으로 캐시 메모리 교체 알고리즘은 “캐시 공간이 꽉 찼을 때, 어떤 데이터를 버릴 것인가”에 대한 규칙이다. 캐시는 크기가 작기 때문에 새 데이터를 넣으려면 기존 것 하나를 버려야 한다. Random은 아무거나 하나를 버리는 방식이라 단순하고 관리 비용이 적다. FIFO는 먼저 들어온 데이터를 먼저 버리는 방식인데, 오래됐지만 자주 쓰이는 데이터도 같이 버려질 수 있다는 문제가 있다. LFU는 가장 적게 사용된 데이터를 버리는데, 최근에 들어왔지만 앞으로 많이 쓰일 데이터가 바로 버려질 수도 있다. LRU는 가장 오래 사용되지 않은 데이터를 버리는 방식으로 실제 사용 패턴과 잘 맞지만, “언제 사용됐는지”를 계속 기록해야 해서 관리 비용이 든다. Optimal은 앞으로 가장 안 쓰일 데이터를 버리는 이상적인 방식이지만, 미래를 알 수 없기 때문에 이론적으로만 존재한다. NUR와 SCR은 “최근에 썼는지 여부”를 비트로 간단히 표시해서, 너무 복잡하지 않게 LRU 비슷한 효과를 내기 위한 절충안이라고 보면 된다.

다음은 페이지 교체에서 생기는 대표적인 문제들이다. Page Fault는 CPU가 어떤 데이터를 쓰려고 했는데, 그 데이터가 메모리에 아예 없을 때 발생하는 상황이다. 이 경우 디스크까지 가야 하므로 매우 느려진다. Demand Paging은 “요청이 있을 때만 페이지를 메모리에 올리자”는 방식 자체를 말하는 용어다. Thrashing은 가장 심각한 상태인데, 페이지가 너무 자주 부족해서 CPU는 거의 일하지 못하고 페이지를 올리고 내리는 일만 반복하는 현상을 뜻한다. 이 상태에서는 시스템이 느려질 뿐 아니라 비정상적으로 보이기도 한다.

마지막으로 이런 문제를 줄이기 위한 해결 방안들이다. Load Control은 프로세스를 너무 많이 동시에 실행하지 않도록 조절해서 메모리 부담을 줄이는 방법이다. Locality는 프로그램이 짧은 시간 동안 특정 코드나 데이터 주변만 집중적으로 사용한다는 성질을 활용하자는 개념이다. Working Set은 “최근 일정 시간 동안 실제로 사용된 페이지들만 메모리에 계속 유지하자”는 전략이다. PFF는 페이지 부재가 너무 자주 발생하면 그 프로세스에 메모리를 더 주고, 거의 발생하지 않으면 메모리를 줄이는 식으로 동적으로 조절하는 방법이다.