탐색으로 돌아가기
Hardware3 / 24 단계

Memory / Cache

메모리와 캐시

CPU는 RAM보다 훨씬 빠르기 때문에, 자주 쓰는 데이터를 L1·L2·L3 캐시에 두어 대기 시간을 줄인다.

메모리는 두 축으로 이해해야 한다. 첫째는 '속도-용량-비용'의 트레이드오프로 배열된 물리적 메모리 계층(memory hierarchy)이고, 둘째는 하나의 프로세스가 바라보는 논리적 가상 메모리 레이아웃(virtual memory layout)이다. 계층은 위에서부터 레지스터(1클럭)→L1 캐시(~1ns)→L2(~4ns)→L3(공유, ~10~40ns)→RAM(~100ns)→SSD(수십 µs)→HDD(수 ms) 순으로, 위로 갈수록 빠르지만 비싸고 작으며, 자주 쓰는 데이터를 상위 계층이 붙잡아 지역성(locality)을 활용해 평균 접근 시간을 줄인다. 한편 각 프로세스는 자신만의 연속된 가상 주소 공간을 갖는데, 낮은 주소부터 코드(Text)·데이터(Data)·BSS·힙(Heap, 위로 성장)·메모리 매핑 영역·스택(Stack, 아래로 성장)이 배치되고, 상위 절반은 커널 영역(kernel space)으로 사용자 코드가 접근할 수 없다. 이 가상 주소를 실제 물리 주소로 바꾸는 하드웨어가 MMU(메모리 관리 장치)이며, 페이지 테이블(page table)을 참조해 페이징(paging)을 수행하고, 최근 변환을 TLB(변환 색인 버퍼)에 캐싱해 매번 페이지 테이블을 뒤지는 비용을 줄인다. 이 구조 덕분에 프로세스 간 메모리 격리, 물리 메모리보다 큰 주소 공간, 요구 페이징(demand paging)이 가능해진다.

내부 구성

레지스터 (Registers)
메모리 계층 최상단. CPU 내부에서 1클럭에 접근되는 가장 빠르고 가장 작은 저장소
L1 캐시 (Level-1 Cache)
코어 전용, 명령(I-cache)·데이터(D-cache) 분리. 수 KB 규모로 ~1ns에 접근되는 최상위 캐시
L2 캐시 (Level-2 Cache)
코어 전용의 통합 캐시. L1보다 크고 느리며(~4ns) L1 미스를 흡수
L3 캐시 (Level-3 Cache)
모든 코어가 공유하는 대용량 캐시(~10~40ns). L2 미스를 받고 멀티코어 캐시 일관성의 조정점 역할
메인 메모리 (RAM / DRAM)
실행 중인 프로그램과 데이터를 담는 주기억장치(~100ns). 휘발성이며 캐시 미스 시 접근됨
보조기억장치 (SSD / HDD)
비휘발성 대용량 저장소(µs~ms). 스와핑·요구 페이징의 백업 저장소이자 파일 시스템의 근거지
코드(Text) 영역
실행할 기계어 명령을 담는 읽기 전용 영역. 여러 프로세스가 공유(코드 재진입)할 수 있음
데이터(Data) 영역
명시적으로 0이 아닌 값으로 초기화된 전역·정적 변수를 담는 영역
BSS 영역 (Block Started by Symbol)
0 또는 미초기화 전역·정적 변수 영역. 실행 파일에는 크기만 기록되고 로드 시 0으로 채워짐
힙 (Heap)
malloc/new로 런타임에 동적 할당되는 영역. 낮은 주소에서 높은 주소로(위로) 성장
메모리 매핑 영역 (Memory-Mapped Segment)
공유 라이브러리(.so/.dll), mmap 파일, 익명 매핑 등이 배치되는 힙과 스택 사이 영역
스택 (Stack)
함수 호출 프레임(지역 변수·매개변수·복귀 주소)을 담는 영역. 높은 주소에서 낮은 주소로(아래로) 성장
사용자 영역 (User Space)
애플리케이션 코드·데이터가 놓이는 낮은 주소 영역. 커널 메모리에 직접 접근 불가
커널 영역 (Kernel Space)
OS 커널 코드·자료구조가 놓이는 상위 주소 영역. 특권 모드에서만 접근 가능해 보호됨
MMU (Memory Management Unit)
CPU가 낸 가상 주소를 페이지 테이블을 참조해 물리 주소로 변환하고 접근 권한을 검사하는 하드웨어
페이지 테이블 (Page Table)
가상 페이지→물리 프레임 매핑(PTE)을 담는 자료구조. 다단계(multi-level)로 구성되어 주소 공간을 관리
TLB (Translation Lookaside Buffer)
MMU 내부의 하드웨어 캐시로, 최근 가상→물리 변환을 저장해 페이지 테이블 워크 비용을 절감
페이지/프레임 (Page / Frame)
가상 메모리를 나누는 고정 크기 단위(보통 4KB)와 그에 대응하는 물리 메모리 단위. 페이징의 기본 블록

핵심 포인트

  • 메모리 계층: 레지스터→L1→L2→L3(공유)→RAM→SSD→HDD, 위로 갈수록 빠르고 비싸고 작음
  • 지역성(temporal/spatial locality)을 이용해 상위 캐시가 하위 계층 접근을 은폐, 평균 접근 시간 단축
  • 프로세스 가상 메모리: Text→Data→BSS→Heap(↑)→mmap→Stack(↓) 순으로 배치
  • Heap은 낮은 주소에서 위로, Stack은 높은 주소에서 아래로 성장 — 가운데 빈 공간을 두고 서로를 향해 자람
  • BSS는 0으로 초기화되는 전역/정적 변수 영역으로, 실행 파일에는 크기 정보만 담겨 용량을 절약
  • 사용자 영역(user space)/커널 영역(kernel space)을 분리해 커널 메모리를 보호
  • MMU가 페이지 테이블로 가상→물리 주소를 변환하고, TLB가 최근 변환을 캐싱해 속도를 확보

심화

메모리 파트에서 가장 자주 빠지고, 면접에서 가장 자주 물어보는 것이 '스택과 힙의 성장 방향'과 'BSS가 왜 따로 존재하는가'다. 스택은 높은 주소에서 아래로, 힙은 낮은 주소에서 위로 성장하며 그 사이의 넓은 빈 공간이 두 영역이 런타임에 자유롭게 확장될 여지를 준다. 스택 오버플로(무한 재귀)나 힙과 스택의 충돌이 왜 발생하는지가 여기서 설명된다. BSS는 0으로 초기화되는 변수들을 위한 영역인데, 이 값들을 실행 파일에 일일이 저장하면 낭비이므로 '크기만' 기록해 두었다가 로더가 로드 시 0으로 채운다 — 그래서 큰 전역 배열을 선언해도 바이너리 크기가 커지지 않는다. Data는 0이 아닌 초기값이 있어 파일에 실제 값이 저장된다는 점에서 BSS와 대비된다. 가상 메모리의 핵심 가치는 격리(isolation)·추상화·초과 커밋(overcommit)이다. 각 프로세스가 동일한 가상 주소 0x400000에서 시작하는 것처럼 보여도 MMU가 서로 다른 물리 프레임으로 매핑하므로 프로세스 간 메모리가 완전히 분리되고, 잘못된 포인터가 다른 프로세스를 건드릴 수 없다. 여기서 반드시 알아야 할 성능 포인트가 TLB다. 페이지 테이블은 보통 4단계(x86-64)로, TLB 미스가 나면 최대 4번의 메모리 접근(page table walk)이 필요해 매우 느리다. 그래서 최근 변환을 TLB에 캐싱하고, 컨텍스트 스위칭 시 TLB 플러시 비용을 줄이려 ASID/PCID를 쓰며, 큰 메모리를 다루는 DB·JVM은 huge page(2MB/1GB)로 TLB 커버리지를 늘려 미스를 줄인다. 또한 요구 페이징(demand paging)과 페이지 폴트(page fault) — 접근한 페이지가 물리 메모리에 없을 때 MMU가 예외를 일으키고 OS가 디스크에서 페이지를 올리는 — 메커니즘까지 연결해 설명하면, '물리 메모리보다 큰 프로그램이 어떻게 실행되는가'라는 질문에 완결적으로 답할 수 있다.

쉽게 말하면 책상 위(캐시)에 자주 보는 책을 두고, 서재(RAM)까지 가는 횟수를 줄이는 것.

면접 예상 질문

#RAM#L1#L2#L3#캐시#지역성