Virtual Memory가 어떻게 작동하는지 궁금해하는 걸 그만두세요!!!
I’m sorry, but I can’t access external websites to retrieve the article’s text. If you provide the content you’d like translated (excluding any code blocks or URLs you want to keep unchanged), I’ll be happy to translate it into Korean while preserving the original formatting.
Scene
화요일 오후 9시 45분이다. 사무실 조명이 어두워지고, 악취 나는 커널 백‑트레이스로 가득 찬 터미널의 차가운 흰빛만이 아르준의 얼굴을 비춘다. 그는 의자에 몸을 늘어뜨리고, 손을 얼굴에 얹은 채 마치 폭발 직전인 듯 보인다.
Maya는 검은 커피와 복잡한 시스템으로 살아가는 시니어 SRE로, 휴게실로 가는 길에 그의 책상을 지나친다. 그녀는 그가 내뿜는 “I’m fucked” 에너지를 보고 멈춘다.
Source: …
Dialogue
Maya:
Yo, Arjun. You still here? You look like you just watched a server rack fall over. What’s up?
Arjun:
(Groans) Maya, man… I’m losing my mind. I’ve been trying to debug this C program for four hours. I keep getting a SIGSEGV at an address that looks like
0x0000800000001234. I thought I understood memory, but this just looks like a random number. My pointers are tripping, and I don’t even know where this data is actually going.
Maya:
(Leans over, looking at the screen) Ah, the classic “I think I know pointers” crisis. Don’t sweat it—everyone hits this wall. You’re looking at a virtual address, but you’re stressed because you can’t see the “real” memory, right?
Arjun:
Exactly. It feels like magic. I know the CPU does something with page tables and the MMU, but it feels like a black box.
Maya:
Alright, pull up a chair. Let’s strip the magic away. Think about it like this: your program is a spoiled brat. It thinks it owns the entire memory space—from zero to the max. That’s the Virtual Address Space.
The actual RAM (the Physical Address) is a shared resource the OS manages.
Arjun:
So the CPU translates them on the fly?
Maya:
Yeah, via the MMU (Memory Management Unit). But it doesn’t translate byte‑by‑byte—that would be insane. It does it in 4 KB chunks called pages.
Arjun:
Okay, so a virtual address is just an index?
Maya:
Sort of. Look at your 64‑bit address. Even though we call it 64‑bit, x86‑64 CPUs usually only use 48 bits for addressing right now.
Arjun:
Wait, why only 48?
Maya:
Because 48 bits gives you 256 TB of address space. We don’t have that much RAM in the server room yet. Here’s the kicker: bits 48 through 63 must be a copy of bit 47.
- If bit 47 is 0, the top bits must be 0.
- If bit 47 is 1, the top bits must be 1.
This is called Canonical Form.
Arjun:
(Looking at his code) Wait… bit 47 in my address
0x000080…is 0, but bit 48 is a 1.
Maya:
Bingo. That’s why you’re fucked. You broke the canonical rule. The CPU didn’t even look at the page table; it just saw that bit 48 didn’t match bit 47 and threw a General Protection Fault → SIGSEGV. Game over.
Arjun:
Holy shit. So the address space is basically split in half?
Maya:
Exactly.
| 영역 | Bit 47 | 주소 범위 | 의미 |
|---|---|---|---|
| Lower half | 0 | 0x0000… | User space |
| Upper half | 1 | 0xffff… | Kernel space |
| “Hole” in middle | — | — | Radioactive (non‑canonical) |
Arjun:
Okay, so if I fix my pointer math and stay in the lower half, how does it get to the actual RAM chip?
Maya:
This is where it gets cool. The MMU takes your virtual address and splits it:
- Offset – the lowest 12 bits (bits 0–11). Since 2¹² = 4096, the offset points to the exact byte inside a 4 KB page.
- Virtual Page Number (VPN) – the remaining higher bits.
Arjun:
And the MMU uses that VPN to “walk” the page table?
Maya:
Right. It’s a four‑level tree. The CPU starts at the base address stored in the CR3 register, uses bits from your address to find the next level, and finally lands on a PTE (Page Table Entry).
Arjun:
(Squinting) So the PTE is the final answer?
Maya:
Yes. But the PTE is a compact structure, not just a plain address. Roughly:
| Bits | Meaning |
|---|---|
| 0–11 | Permission and status flags |
| 12–51 | PFN (Physical Frame Number) |
| 63 | NX (No‑Execute) bit |
Arjun:
Wait, so you’re saying the first 12 bits are just used for permissions and… the other bits do the actual pointing?
Maya:
Exactly! The PFN is the real, physical address of the pa
Source: …
RAM에 저장된 페이지 프레임 번호(PFN)는 12비트 오른쪽으로 시프트되어 공간을 절약합니다. CPU가 해당 플래그를 확인해 권한을 확인하면 다음을 수행합니다:
- PFN을 가져오고,
- 이를 12비트 왼쪽으로 시프트(12개의 0을 추가)하여 베이스 물리 주소를 얻고,
- 원래의 오프셋을 더합니다.
결과 → 메모리 버스상의 실제 물리 바이트 주소.
Arjun:
그래서: 가상 주소 → PTE → PFN(실제 물리 페이지) → + 오프셋 → 실제 물리 바이트.
Maya:
정확해. 더 이상 간접 참조가 없어. 이것이 최종 번역이야.
Arjun:
와, 그 비트 시프트는 정말 영리하네. 물리 프레임 주소가 항상 열 개의 0으로 끝난다는 걸 알고 있었기 때문에, 오프셋 12비트를 PTE 안의 권한 비트로 재활용한 거잖아.
Maya:
딱 맞아. 이제 PTE 레이아웃을 완전히 이해했어. 그런데 Present 비트(비트 0)가 0이면 어떻게 될까?
Arjun:
MMU가 페이지를 찾을 수 없다는 거야?
Maya:
맞아—페이지 폴트. CPU는 현재 작업을 멈추고 OS에 신호를 보낸다. 커널의 페이지 폴트 핸들러는 CR2 레지스터를 확인해 어디로 접근하려 했는지 확인한다. 페이지가 스와핑되어 있었다면, 커널은 조용히 해당 페이지를 RAM에 다시 로드하고 PTE를 업데이트한 뒤 프로그램을 계속 실행하게 한다.
Arjun:
그런데 읽기 전용 페이지나 널 포인터에 쓰려고 하면?
Maya:
그때 커널은 불법적인 동작을 감지하고 SIGSEGV를 보낸다—오늘 밤 네게 일어난 일과 정확히 같은 상황이지.
Arjun:
(웃으며) 비정규 주소에 접근했기 때문이야. 페이지 테이블 검사 단계에 도달하기도 전에 말이야.
Maya:
정확해. 마지막으로 TLB(Translation Lookaside Buffer)를 잊지 마. 매 메모리 접근마다 4단계 페이지 테이블을 탐색한다면 컴퓨터가 엄청 느려질 거야. TLB는 CPU 내부에 있는 아주 작고 초고속 캐시로, 최근에 사용된 가상 → 물리 변환을 기억한다.
대화 종료.
Arjun: 현대 컴퓨터가 빠른 이유는 바로 그 때문이야.
Arjun: 그래서: TLB 확인 → 미스이면 페이지 테이블 탐색 → PTE 플래그 확인 → 물리 주소 계산 → 데이터 가져오기.
Maya: 맞아. 이제 그 백트레이스 보는 걸 그만두고 포인터 연산을 고쳐, 그리고 같이 밥이나 먹자. 내가 쏠게.
Arjun: (노트북을 닫으며) 고마워, Maya. 이제 엔진 아래에서 무슨 일이 일어나는지 알 것 같아. 더 이상 “망했어”가 아니라 “배우고 망했어”야.
Maya: (웃으며) 그게 바로 정신이야, 얘. 가자.