#14 변환참조버퍼 TLB _ 기본편
매번 Page Table 뒤지면 너무 느리잖아 — TLB
오늘 이 글에서는 TLB가 정확히 뭘 캐싱하는 건지, TLB 안에 뭐가 들어있는지, 그리고 TLB 하나 때문에 속도가 얼마나 차이 나는지까지. 딱 기본만 다루고, 더 깊은 내용은 다음 글(TLB 심화)에서 이어갈게.
지난 글에서 페이징의 문제로 "메모리 접근마다 Page Table을 한 번 더 읽어야 한다"는 걸 짚었잖아. 이 추가 접근을 없애려고 나온 게 TLB야.
TLB가 뭐야
Translation Lookaside Buffer의 약자야. 번역하면 변환참조버퍼, 변환우선참조버퍼, 변환색인버퍼 이렇게도 불리는데 다 같은 걸 가리켜.
한마디로 정리하면, Page Table을 캐싱해두는 저장 장치야. CPU 캐시가 메모리 접근을 빠르게 해주는 것처럼, TLB는 주소 변환을 빠르게 해줘. MMU 내부에 자리 잡고 있고, 최근에 변환했던 VPN→PFN 매핑을 몇 개 기억해뒀다가, 같은 VPN이 또 들어오면 Page Table을 안 뒤지고 바로 답을 줘.
요즘 CPU들은 TLB도 계층으로 나눠서 둬. L1 TLB, L2 TLB처럼 여러 단계로 존재할 수 있어 — CPU 캐시가 L1, L2, L3로 나뉘는 것처럼, TLB도 작고 빠른 L1이랑 좀 더 크고 느린 L2를 같이 쓰는 구조가 흔해.
TLB가 꽉 차면 뭔가를 밀어내야 하는데, 이때 쓰는 교체 정책은 아키텍처마다 달라. LRU(가장 오래 안 쓴 걸 밀어내는 방식)를 쓰는 경우도 있고, 하드웨어 구현 비용 때문에 라운드로빈이나 랜덤 방식을 쓰는 경우도 있어. LRU가 개념적으로 가장 자연스럽고 많이 언급되긴 하지만, "TLB는 무조건 LRU를 쓴다"고 단정할 순 없어.
TLB는 어떻게 동작해
가상 주소가 CPU에서 나오면, TLB부터 확인해. 있으면 바로 물리 주소를 얻고, 없으면 그제서야 Page Table을 뒤져. 그마저도 없으면(페이지가 디스크에 있으면) 디스크에서 읽어와야 해.

TLB에서 못 찾았는데 Page Table에서 찾았다면, 그 결과를 TLB에 새로 저장해둬. 그래야 다음번에 같은 주소가 또 들어오면 이번엔 TLB에서 바로 찾을 수 있으니까. Page Table에도 없다면 그 페이지가 디스크로 밀려나 있다는 뜻이고, 디스크에서 읽어온 뒤에 Page Table이랑 TLB를 둘 다 갱신해줘.
면접 포인트 ( •̀ ω •́ )✧
Q. 전체적인 페이지 탐색 과정을 설명해 주세요.
CPU가 가상 주소를 요청하면 먼저 TLB를 확인합니다. TLB에 있으면(TLB Hit) 곧바로 물리 주소를 얻습니다. TLB에 없으면(TLB Miss) Page Table을 조회하는데, 여기서 찾으면 물리 주소를 얻으면서 동시에 TLB도 갱신합니다. Page Table에도 없으면 그 페이지가 디스크로 밀려나 있다는 뜻이라 디스크에서 페이지를 읽어온 뒤 Page Table과 TLB를 모두 갱신하고 나서야 물리 주소를 얻습니다.
TLB 구조: 안에 뭐가 들어있어
TLB는 기본적으로 key-value 형태로 동작해.
VPN (Virtual Page Number)
TLB의 key 역할이야. CPU가 요청하는 가상 주소는 VPN이랑 offset(VPO)으로 나뉘는데, TLB는 이 중 VPN만 뽑아서 내부를 검색해. 참고로 "Frame"이라는 표현은 물리 메모리 쪽에서만 써 — 가상 주소 공간에서는 그냥 "page"고, 물리 메모리에 배치될 때 비로소 "page frame"이 되는 거야. 그래서 정확한 이름은 Virtual PageFrameNumber가 아니라 그냥 Virtual Page Number야.
PFN / PPN (Physical Frame Number / Physical Page Number)
VPN이랑 1:1로 매칭되는 TLB의 value야. 요청한 가상 주소에 해당하는 실제 메모리 위치를 담고 있고, 여기에 offset을 합치면 물리 주소가 완성돼. PFN이랑 PPN은 교재마다 부르는 이름만 다를 뿐 같은 걸 가리켜.
그 외 상태 비트들
- valid: hit인지 miss인지 표시하는 비트. 시스템 시작 시점엔 전부 invalid로 초기화돼있어
- protection: 이 페이지에 read/write/execute 중 뭐가 허용되는지 표시하는 일종의 보호 비트
- dirty: 이 페이지 내용이 최초 적재 이후 수정된 적이 있는지 나타내는 비트. 정확히는 물리 페이지 자체의 수정 여부를 추적하는 비트인데, 하드웨어가 쓰기 접근이 일어날 때마다 TLB 엔트리에 바로 표시해두고, 나중에 이 정보를 Page Table에도 반영해
- ASID(Address Space ID): 프로세스마다 부여되는 ID야. 단일 프로세스 환경에서는 VPN이 겹칠 일이 없으니까 필요 없는데, 여러 프로세스가 TLB 하나를 공유하는 환경에서는 문제가 생겨. 프로세스 A의 VPN 3이랑 프로세스 B의 VPN 3은 완전히 다른 물리 주소를 가리키는데, ASID가 없으면 TLB가 이 둘을 구분 못 해. ASID가 나오기 전에는 Context Switch가 일어날 때마다 TLB를 통째로 비워버리는 방법을 썼는데, 이게 오버헤드가 너무 커서 프로세스별로 ID를 매겨서 TLB 안에서 같이 관리하는 ASID가 고안됐어.
면접 포인트 ( •̀ ω •́ )✧
Q. TLB 히트, TLB 미스, 페이지 폴트의 경우 속도 차이는 어느 정도인가요?
TLB Hit는 사실상 1사이클 안팎으로 끝나서 거의 공짜에 가깝습니다. TLB Miss가 나서 Page Table을 뒤지는 경우(페이지 폴트는 아직 아닌 상태)는 보통 수십 사이클 정도가 걸리고요. 근데 Page Fault까지 나서 디스크에서 읽어와야 하면 디스크 접근 자체가 밀리초 단위라 수백만 사이클 이상이 걸립니다. 그래서 TLB Hit랑 Page Fault 사이의 속도 차이는 수만 배에서 수십만 배까지도 벌어질 수 있습니다.
이 수치, 감으로 말한 게 아니라 실제로 TLB는 fully associative 캐시로 설계돼서 1사이클 안에 조회가 끝나도록 만들어지고, 그럼에도 불구하고 TLB hit rate는 보통 99% 이상으로 알려져 있어. 이렇게 hit rate가 높으니까 TLB 하나 추가한 것만으로 평균 메모리 접근 시간이 크게 줄어드는 거야.
TLB는 결국 "최근에 쓴 주소 변환 결과를 기억해뒀다가 재활용하자"는 캐싱 아이디어고, 이게 먹히는 이유는 프로그램이 실제로 접근하는 주소가 굉장히 좁은 범위에 몰려있기 때문이야(지역성). 근데 이 좁은 범위조차 Context Switch가 일어나면 완전히 달라지고, TLB가 여러 레벨로 쌓이면 또 나름의 복잡한 문제들이 생겨. 그 얘기는 다음 글, TLB 심화편에서 이어갈게.
'Study > [ OS ]' 카테고리의 다른 글
| #16 Paging: Smaller Table (0) | 2026.07.15 |
|---|---|
| #15 변환참조버퍼 TLB _ 심화편 (0) | 2026.07.15 |
| #13 페이징 (Paging) (0) | 2026.07.15 |
| #12 Segmentation (0) | 2026.07.15 |
| #11 주소 변환(Address Translation) (0) | 2026.07.15 |
흐이서
Writer공순이 흐이서