한양과학기술고등학교

에듀테크 프로젝트 대시보드

지역성의 원리

지역성의 원리 (Locality of Reference)

캐시는 메인 메모리보다 훨씬 작다. 그런데도 대부분의 프로그램에서 캐시 히트율은 90%를 훌쩍 넘는다. 어떻게 "일부만 담아 둔 작은 저장소"가 이렇게 잘 맞아떨어질 수 있을까? 그 답이 지역성의 원리 — 프로그램이 메모리에 접근하는 패턴은 무작위가 아니라 편향되어 있다는 경험적 사실이다.

1. 왜 계층 구조가 통하는가

이상적으로는 모든 데이터를 레지스터처럼 빠른 곳에 두고 싶다. 하지만 빠른 메모리는 비싸고 칩 면적을 많이 먹어서 용량이 작을 수밖에 없다. 그래서 컴퓨터는 레지스터 → 캐시 → RAM → 디스크로 갈수록 느려지지만 커지는 계층을 쌓는다.

문제는 이거다 — 캐시가 전체 메모리의 1% 미만인 경우도 흔한데, 그 1%에 "지금 필요한 데이터"가 들어있을 확률이 왜 이렇게 높을까? 정답: 프로그램은 메모리를 균등하게 건드리지 않는다. 방금 쓴 변수를 또 쓰고, 배열은 순서대로 훑고, 함수는 정해진 코드 블록을 반복 실행한다. 이 편향에는 이름이 두 개 붙어 있다 — 시간 지역성과 공간 지역성. 캐시는 이 두 가지 편향에 통째로 베팅한 하드웨어다.

핵심: 캐시가 작아도 잘 맞는 이유는 캐시가 똑똑해서가 아니라, 프로그램의 접근 패턴 자체가 예측 가능하기 때문이다. 지역성이 없는 프로그램(완전 무작위 접근)이라면 캐시는 무용지물이 된다.

2. 시간 지역성 — 방금 쓴 걸 또 쓴다

"최근에 접근한 데이터는 곧 다시 접근될 가능성이 높다." 반복문 안의 카운터, 합계를 누적하는 변수, 재귀 호출의 스택 프레임이 대표적이다. 아래 합계 계산 코드를 한 줄씩 재생해 보면, 변수 합계와 i가 매 반복마다 계속 재사용되는 게 보인다 — 이 두 변수는 한 번 레지스터/캐시에 올라가면 반복문이 끝날 때까지 계속 히트한다.


      
합계 (sum)
0
재사용 0회
i
–
재사용 0회
같은 변수 슬롯을 반복해서 읽고 쓰는 것 — 이게 시간 지역성이다. 레지스터/L1 캐시에 합계, i가 상주하면 매 반복 메모리까지 안 가도 된다.

3. 공간 지역성 — 근처도 곧 쓴다

"한 번 접근한 데이터 근처의 데이터도 곧 접근될 가능성이 높다." 배열을 순서대로 훑는 게 대표적이다. 캐시는 이 편향을 이용해서 바이트 하나가 아니라 블록(캐시 라인) 단위로 메모리를 통째로 가져온다 — 아래 그리드에서 4칸씩 구분선이 캐시 라인 경계다.

접근 패턴:
현재 접근 이미 접근함(같은 라인) 라인을 벗어난 새 접근
순차 접근을 재생해 보면 한 캐시 라인(4칸)에 들어온 뒤로 3번의 추가 접근이 공짜로 캐시에서 처리된다. 무작위 접근은 매번 다른 라인으로 튀어서 이 이득이 사라진다.

4. 핵심 실험 — 캐시 히트율 시뮬레이터

16개 블록짜리 배열과 4줄짜리 작은 캐시를 두고, 순차 접근과 무작위 접근을 각각 20번 재생해서 히트율을 직접 비교해 보자. 캐시가 작아도(전체의 25%) 접근 패턴이 좋으면 히트율이 압도적으로 높다는 게 눈으로 보일 것이다.

순차 접근

접근
0
히트
0
히트율
–

무작위 접근

접근
0
히트
0
히트율
–
두 패턴 모두 캐시 크기·미스 시 채우는 블록 크기(캐시 라인 = 4개 원소)는 동일하다. 차이는 오직 접근 순서뿐인데도 히트율이 극단적으로 갈린다 — 이게 지역성이 성능에 미치는 힘이다.

5. 실전 예시 — 2차원 배열, 어느 방향으로 훑을까

2차원 배열은 메모리에 1차원으로 한 줄씩 이어 붙여 저장된다(행 우선 저장, row-major). 그래서 행 방향으로 순회하면 주소가 계속 이어지지만(공간 지역성 ↑), 열 방향으로 순회하면 매번 한 행 전체 너비만큼 점프한다(공간 지역성 ↓).

행 우선 순회 — 메모리 주소가 연속
열 우선 순회 — 매번 큰 폭으로 점프
# 빠름: 행 우선 — 메모리 상 연속된 주소를 그대로 따라감
for i in range(N):
    for j in range(N):
        total += matrix[i][j]   # 캐시 라인 하나로 여러 번 히트

# 느림: 열 우선 — 매 접근이 한 행 너비(N칸)만큼 점프
for j in range(N):
    for i in range(N):
        total += matrix[i][j]   # 매번 새 캐시 라인 → 미스 폭증
기억할 것: 같은 결과를 계산하는 코드라도, 반복문 순서만 바꿨을 뿐인데 공간 지역성이 완전히 달라진다. 큰 배열일수록 이 차이는 실제 실행 시간에서 몇 배 차이로 드러난다.

6. 관련 페이지

한 줄 정리: 캐시가 작아도 잘 맞는 이유는 마법이 아니라 프로그램의 습관 때문이다 — 방금 쓴 걸 또 쓰고(시간 지역성), 쓴 것 근처를 곧 쓴다(공간 지역성). 메모리 계층 구조, 캐시 라인, 배열 순회 순서까지 — 컴퓨터 구조의 성능 최적화 대부분이 이 두 문장 위에 서 있다.