본문으로 건너뛰기

버그 제보

이상한 점을 알려 주시면 고칠게요. 지금 보고 있는 페이지와 브라우저 정보가 함께 담겨요.

페이지:

Computer Science

캐시 메모리와 MMU

작성 2026. 10. 12.추가
목차10개 항목
출처와 참고

교체 정책·성능 지표·캐시 친화적 코드는 「캐시가 동작하는 아주 구체적인 원리」로 보강했다. 「캐시 메모리」 절은 강민철의 「혼자 공부하는 컴퓨터 구조+운영체제」 강의(한빛미디어)를 바탕으로 보강했다. 캐시 계층별 역할, 라인 크기의 트레이드오프, 하드웨어 교체 정책 부분은 fru1tworld/cs-basic 모의 면접 질문 목록을 점검해 빠진 개념을 보강했다. 평균 접근 시간 계산(1·2단계), 요구 인출과 선인출, 캐시 용량의 트레이드오프는 고려사이버대학교 「컴퓨터구조」(2024-1학기) 강의 내용으로 보강했다.

캐시와 가상 메모리는 같은 아이디어를 메모리 계층의 서로 다른 층에 적용한 것이다. 캐시는 "느린 메인 메모리를 빠르게", 가상 메모리는 "작은 메인 메모리를 크게" 보이게 만든다. 둘 다 프로그램이 최근에 쓴 데이터나 그 근처를 다시 쓰는 경향(지역성)에 기대고 있다. 이 노트는 그중 하드웨어가 담당하는 부분, 즉 캐시 회로와 MMU를 다룬다.

캐시 메모리

  • 메인 메모리보다 훨씬 빠르고 용량은 훨씬 작다.
  • 보통 L1·L2는 코어 안에, L3는 여러 코어가 공유하는 계층 구조다. 코어에서 멀수록 크고 느리다(L1 < L2 < L3 < 메인 메모리).
  • L1은 다시 명령어만 담는 L1I와 데이터만 담는 L1D로 나누기도 한다(분리형 캐시, split cache). 명령어 인출과 데이터 접근이 한 캐시를 놓고 다투지 않아 L1을 더 빠르게 쓸 수 있다. L2부터는 보통 둘을 함께 담는 통합 캐시다.
  • 계층마다 맡는 일이 다르다. 크기·지연은 세대마다 다르므로 자릿수로만 본다.
계층위치크기지연역할
L1코어마다, 명령어(L1I)·데이터(L1D) 분리수십 KB4~5클럭매 명령어가 쓰는 데이터를 거의 지연 없이 공급
L2코어마다(일부 설계는 코어 몇 개가 공유)수백 KB~수 MB10~20클럭L1에서 놓친 것을 받아 주는 완충
L3 (LLC)칩의 모든 코어가 공유수십 MB 이상수십 클럭코어 사이의 데이터 공유, 메모리 접근 줄이기
  • 코어마다 L1·L2를 따로 두면 같은 주소의 사본이 여러 코어에 생겨, 한 코어가 값을 바꾸면 다른 코어의 사본과 어긋날 수 있다. 이를 맞추는 캐시 일관성(MESI)은 캐시를 고려한 코드에 있다.
  • CPU는 주소만 내보낼 뿐, 데이터가 캐시에 있는지 메인 메모리에 있는지 신경 쓰지 않는다. 이를 연결하는 것이 주소 매핑이다.
    • 캐시 히트: 캐시에 있음 → 바로 전달
    • 캐시 미스: 없음 → 메인 메모리에서 가져와 캐시에 채움
  • 히트율 = 히트 횟수 / 전체 접근 횟수. 실제 프로그램은 지역성이 있어 히트율이 높게 유지되고, 캐시가 효과를 내는 것도 이 덕분이다.
  • 캐시가 기대는 참조 지역성은 두 가지다. 시간 지역성은 최근에 접근한 곳(예: 반복해서 쓰는 변수)에 다시 접근하는 경향이고, 공간 지역성은 접근한 곳 근처(예: 배열의 다음 원소, 함께 모여 있는 관련 데이터)에 접근하는 경향이다. 분기가 없으면 명령어가 저장된 순서대로 인출된다는 순차 지역성을 따로 꼽기도 한다(공간 지역성의 특수한 경우).
  • 미스가 났을 때 필요한 블록만 가져오는 것이 요구 인출(demand fetch), 곧 쓸 것으로 예측되는 블록까지 미리 가져오는 것이 선인출(prefetch)이다. 선인출은 지역성이 높을수록 효과가 크다.
  • 캐시 용량은 클수록 히트율이 오르지만 비싸고, 주소 해독·인출 회로가 복잡해져 히트 시간 자체가 조금 늘어난다. L1을 작게 두는 이유다.
  • 캐시 설계의 목표는 네 가지로 정리된다. 히트율을 최대로, 히트 시간을 최소로, 미스 때의 지연을 최소로, 그리고 메인 메모리와의 일관성을 적은 비용으로 유지한다.

주소 매핑 방식

방식동작장단점
연관 매핑 (fully associative)주소(태그)와 데이터를 함께 저장하고, 들어온 주소를 모든 항목과 동시에 비교어디든 저장 가능해 유연하지만 비교 회로가 비쌈
직접 매핑 (direct)주소를 태그 + 인덱스로 나누고 인덱스로 캐시 위치를 바로 결정, 태그만 비교단순·저렴하지만 같은 인덱스를 쓰는 주소끼리 계속 충돌
집합 연관 매핑 (set-associative)한 인덱스(집합)에 2개·4개 등 여러 블록을 저장 (2-way, 4-way)직접 매핑의 충돌을 줄이는 절충안. way를 끝까지 늘리면 연관 매핑과 같아짐

블록 단위로 매핑할 때는 주소를 태그 / 인덱스(블록) / 블록 내 워드로 나눈다.

블록(캐시 라인) 크기도 트레이드오프다. 라인을 키우면 미스 한 번에 이웃 데이터를 더 가져와 공간 지역성을 더 살리지만, 미스 페널티(전송 시간)가 커지고, 같은 용량에 담는 라인 수가 줄어 충돌 미스가 늘며, 서로 다른 변수가 한 라인에 묶이는 거짓 공유도 잦아진다. 대부분의 CPU는 64바이트에서 균형을 잡는다(Apple M 시리즈는 128바이트).

쓰기 정책

정책동작특징
Write-through캐시와 메인 메모리에 동시에 기록메모리가 항상 최신이라 안전하지만 쓰기가 느림
Write-back캐시에만 기록하고, 블록이 교체될 때 메모리에 반영쓰기가 빠르지만 반영 전 장애 시 데이터 손실 위험, 일관성 관리 필요

쓰기 미스가 나면 보통 그 블록을 캐시로 가져온 뒤 쓴다(write-allocate). Write-back은 블록마다 dirty 비트를 두어, 바뀐 블록만 교체할 때 메모리에 쓴다.

교체 정책과 성능 지표

집합 연관·연관 매핑에서 집합이 꽉 차면 어떤 블록을 내보낼지 정해야 한다. 먼저 들어온 블록을 내보내는 FIFO, 가장 오래 쓰지 않은 블록을 내보내는 LRU가 대표적이다. LRU는 운영체제의 페이지 교체와 소프트웨어 캐시에도 같은 생각으로 쓰인다. 다만 하드웨어는 모든 접근의 순서를 정확히 기록하기 비싸서, way가 많으면 트리 모양 비트로 근사한 pseudo-LRU나 한 번 쓰고 마는 데이터에 강한 RRIP 계열, 또는 무작위 교체를 쓴다. 참조 횟수를 세야 하는 LFU는 CPU 캐시에서 쓰지 않는다.

캐시 성능은 히트율 하나보다 평균 메모리 접근 시간(AMAT) 으로 본다.

AMAT = 히트 시간 + 미스율 × 미스 페널티

히트율 H, 캐시 접근 시간 Tc, 메인 메모리 접근 시간 Tm으로 쓰면 Ta = H × Tc + (1 − H) × Tm이다(미스 때 Tm만 걸린다고 본 단순화). Tc = 10ns, Tm = 100ns에서 H가 0.5면 55ns, 0.9면 19ns, 0.99면 10.9ns로, 히트율이 오를수록 평균은 캐시 속도에 붙는다.

캐시가 두 단계면 L1에서 놓친 접근 가운데 L2가 받아 주는 비율(지역 히트율) H2를 써서 다음과 같이 계산한다.

Ta = H1 × T_L1 + (1 − H1) × H2 × T_L2 + (1 − H1)(1 − H2) × Tm

L1은 빠르지만 작아 L2보다 히트율이 낮다. L1의 모든 내용을 L2에도 두는 구성을 포함형(inclusive) 캐시라 하며, 이때 L2는 L1의 상위 집합이다.

태그 비교가 추가되면 히트 시간이 늘어나므로, 태그 확인과 데이터 읽기를 병렬로 해서 줄이기도 한다.

캐시 친화적인 코드

캐시는 바이트가 아니라 블록(캐시 라인, 보통 64바이트) 단위로 가져오므로, 메모리에 놓인 순서대로 접근하는 코드가 빠르다. 행 우선 순회, 루프 타일링, 배열과 연결 리스트의 차이, 거짓 공유는 캐시를 고려한 코드에 있다.

초기화

각 캐시 항목에 valid 비트를 두고, 시작할 때 모두 0으로 만들어 "아직 유효한 데이터가 없음"을 표시한다. 메모리에서 데이터를 채울 때 1로 바꾼다.

가상 메모리와 하드웨어의 분업

가상 메모리는 보조 기억 장치를 메인 메모리의 연장처럼 써서, 프로그램이 실제 물리 메모리보다 큰 주소 공간을 가진 것처럼 동작하게 하는 기법이다. 운영체제가 정책을 정하고, 하드웨어(MMU)가 매 메모리 접근마다 그 정책을 실행한다.

  • 페이지 테이블로 가상 주소를 물리 주소로 바꾸는 구조, 세그멘테이션, TLB는 메모리 관리에 정리했다.
  • 페이지가 메모리에 없을 때 일어나는 페이지 폴트 처리와 FIFO·LRU·Clock 같은 교체 알고리즘은 가상 메모리에 있다.

아래부터는 그 분업에서 MMU가 맡는 몫만 본다.

메모리 관리 장치 (MMU)

여러 프로그램이 동시에 메모리를 쓰는 환경에서 MMU의 역할은 세 가지다.

  1. 동적 재배치: 가상 주소를 실행 시점에 물리 주소로 변환한다.
  2. 공유: 컴파일러나 라이브러리처럼 공통 프로그램을 사용자마다 복사하지 않고 하나만 두고 함께 쓴다.
  3. 보호: 다른 프로그램이나 운영체제 영역에 허락 없이 접근하지 못하게 막는다.

변환은 테이블 조회라서 한 번의 메모리 접근에 여러 번의 테이블 참조가 따라붙는다. 그래서 MMU는 최근 변환 결과를 연관 메모리에 담아 두는 TLB(Translation Lookaside Buffer) 를 끼고 동작한다. TLB도 결국 "주소 변환 결과의 캐시"이므로, 캐시 메모리 절의 매핑·히트율 개념이 그대로 적용된다. TLB 미스 처리와 다단계 페이지 테이블은 메모리 관리에 있다.

메모리 보호 필드

세그먼트 테이블 항목에 베이스 주소 외에 길이 필드(범위를 넘는 접근 차단)와 보호 필드(접근 권한)를 둔다.

권한용도
읽기/쓰기 모두 허용일반 사용자 데이터
읽기 전용공유 라이브러리·유틸리티 보호
실행 전용프로그램 복사 방지
시스템 전용운영체제 영역 보호

핵심 정리

  • 캐시: 매핑(연관/직접/집합 연관)과 쓰기 정책(write-through/back)이 핵심이다. 평균 접근 시간은 H × Tc + (1 − H) × Tm으로, 히트율이 높을수록 캐시 속도에 가까워진다.
  • 가상 메모리는 OS가 정책(교체·할당)을, MMU가 실행(주소 변환·보호)을 맡는 분업 구조다.
  • MMU는 재배치·공유·보호를 맡고, TLB로 주소 변환을 빠르게 한다. 보호는 세그먼트 테이블의 길이·보호 필드로 구현한다.

캐시가 놓인 위치는 메모리 계층 구조를 참고한다.

관련 노트: 캐시를 고려한 코드, 메모리 관리

원본 기록6

댓글

GitHub 계정으로 댓글을 남길 수 있어요.