CHAPTER 06

운영체제

프로세스 상태, 메모리 구조, 컨텍스트 스위칭부터 가상메모리, 스케줄링, 데드락까지 — OS 핵심 개념을 인터랙티브 시각화로 완전히 이해합니다.

프로세스 상태메모리 레이아웃컨텍스트 스위칭 메모리 관리가상메모리스케줄링데드락
PROC

프로세스 상태 (Process State Diagram)

프로그램을 실행하면 OS는 프로세스를 생성합니다. 프로세스는 생명 주기 동안 5가지 상태를 거칩니다. CPU가 하나뿐이라도 여러 프로세스가 동시에 실행되는 것처럼 보이는 건 이 상태 전환 덕분입니다.

NEW
프로세스가 막 생성된 상태. OS가 PCB를 할당하고 초기화합니다.
READY
CPU를 받을 준비가 된 상태. 레디 큐에서 스케줄러를 기다립니다.
RUNNING
실제로 CPU에서 명령어가 실행 중인 상태. 단일 코어에서는 1개만 가능.
WAITING
I/O 완료, 이벤트 등을 기다리는 상태. CPU를 소비하지 않습니다.
TERMINATED
실행이 끝났거나 강제 종료된 상태. OS가 PCB와 자원을 회수합니다.
PID이름현재 상태우선순위실행 시간
버튼을 눌러 프로세스의 상태를 전환해 보세요. 선택된 프로세스(파란 테두리)에 상태 전환이 적용됩니다.
💡 Tip: 실제 OS에서 NEW→READY는 fork()로, RUNNING→WAITING은 read()나 sleep() 같은 블로킹 시스템 콜로 발생합니다.
MEM

프로세스 메모리 구조 (Memory Layout)

실행 중인 프로그램은 메모리에서 정해진 영역에 나눠 저장됩니다. 코드는 코드 세그먼트, 전역변수는 데이터 세그먼트, 동적 할당은 힙(위로), 함수 호출 스택은 스택(아래로). 힙과 스택이 만나면 메모리 오류가 납니다.

0xFFFF (High)
↓ STACK (grows down)
빈 공간
↑ HEAP (grows up)
BSS
초기화 안 된 전역변수
DATA
초기화된 전역/정적 변수
CODE (TEXT)
읽기전용 실행 코드
0x0000 (Low)
포인터 현황
SP (스택 포인터)SP = 0xFFFF
HP (힙 포인터)HP = 0x4000
스택과 힙이 충돌 위험! Stack Overflow 또는 Heap Overflow 가능성이 있습니다.
세그먼트 설명
STACK함수 호출 시 지역변수, 반환주소, 매개변수 저장
HEAPmalloc/new로 동적 할당. 프로그래머가 직접 관리
BSSint g; 처럼 초기값 없는 전역변수 (0으로 자동초기화)
DATAint g=5; 처럼 초기값 있는 전역/static 변수
CODE컴파일된 기계어 명령어. 읽기 전용(쓰면 segfault)
💡 Tip: 재귀 함수를 무한히 호출하면 스택이 힙 방향으로 계속 자라다가 stack overflow가 발생합니다. C에서 free()를 잊으면 힙이 누수(memory leak)됩니다.
CTX

컨텍스트 스위칭 (Context Switch)

CPU는 1초에 수백~수천 번 프로세스를 교체합니다. 교체할 때마다 현재 프로세스의 '상태'(레지스터, PC, 스택 포인터 등)를 PCB에 저장하고, 다음 프로세스의 상태를 복원합니다. 이 오버헤드 시간 동안 CPU는 유용한 작업을 하지 못합니다.

CPU 타임라인 (시간 →)
Process A 실행
Process B 실행
오버헤드 (비생산)
PCB — Process A
PID1
PC0x0040
SP0xFF80
AX0x0005
StateRUNNING
PCB — Process B
PID2
PC0x00A0
SP0xFE00
AX0x001F
StateREADY
0
컨텍스트 전환 횟수
0 ms
낭비된 오버헤드
A
현재 실행 중인 프로세스
💡 Tip: 컨텍스트 스위치는 CPU에 저장된 레지스터 전체(수십~수백 개)를 메모리에 쓰고 읽는 작업입니다. 이 오버헤드가 크기 때문에 OS는 타임슬라이스(quantum)를 너무 짧게 설정하지 않습니다.
ALLOC

메모리 관리 (Memory Allocation)

OS는 여러 프로세스에게 물리 메모리를 나눠줍니다. 프로세스들이 할당·해제를 반복하면 메모리 곳곳에 사용할 수 없는 작은 구멍들이 생기는 외부 단편화(fragmentation)가 발생합니다. 메모리 압축(compaction)으로 이를 해소할 수 있지만 비용이 큽니다.

메모리 상태: 비어있음 | 단편화: 0%
💡 Tip: 단편화 지수가 높을수록 비어있는 블록이 잘게 쪼개져 큰 프로세스를 할당하기 어렵습니다. 압축은 실행 중인 프로세스를 이동시켜야 하므로 비용이 큽니다.
VM

가상메모리 (Virtual Memory)

프로세스는 실제 물리 메모리보다 훨씬 큰 메모리 공간을 사용할 수 있습니다. OS는 페이지 테이블을 통해 가상 주소를 물리 주소로 변환합니다. 필요한 페이지가 물리 메모리에 없으면 페이지 폴트(Page Fault)가 발생하고 디스크에서 로드합니다.

가상 페이지 (8개)
페이지 테이블
물리 프레임 (4개)
0
PAGE HIT
0
PAGE FAULT
HIT RATE
가상 페이지를 클릭하거나 버튼을 눌러 접근을 시뮬레이션하세요.
💡 Tip: 물리 프레임이 꽉 찼을 때 FIFO 알고리즘은 가장 먼저 들어온 페이지를 교체합니다. 실제 OS는 LRU(가장 오래 미사용)나 Clock 알고리즘을 사용합니다.
SCHED

프로세스 스케줄링 (Process Scheduling)

여러 프로세스가 CPU를 원할 때 OS는 어떤 순서로 실행할지 결정합니다. FCFS는 단순하지만 짧은 작업이 오래 기다릴 수 있고, SJF는 평균 대기 시간을 최소화하며, Round Robin은 공정성을 보장합니다.

레디 큐 (Ready Queue) — 실행 대기 중인 프로세스
스케줄러를 실행하면 레디 큐가 표시됩니다
CPU:
유휴
← 디스패처
프로세스 정보
Gantt 차트
💡 Tip: WT(대기시간) = 반환시간 - 버스트시간. TAT(반환시간) = 완료시간 - 도착시간. SJF는 starvation(기아) 문제가 있어 짧은 작업이 계속 오면 긴 작업은 영원히 기다릴 수 있습니다.
DEADLOCK

데드락 (Deadlock)

두 개 이상의 프로세스가 서로 상대방이 가진 자원을 기다리며 영원히 멈추는 상태입니다. 식사하는 철학자 문제로 데드락의 발생 과정과 해결책을 시뮬레이션합니다.

데드락 4가지 필요조건 — 클릭해서 체크/해제
CONDITION 01
상호배제 (Mutual Exclusion)
자원은 한 번에 한 프로세스만 사용 가능. 포크는 한 철학자만 쥘 수 있습니다.
CONDITION 02
점유 및 대기 (Hold & Wait)
자원을 점유한 채로 다른 자원을 기다림. 왼쪽 포크를 쥔 채 오른쪽 포크를 기다립니다.
CONDITION 03
비선점 (No Preemption)
자원을 강제로 빼앗을 수 없음. 철학자가 포크를 자발적으로 내려놓을 때만 반납됩니다.
CONDITION 04
순환 대기 (Circular Wait)
P0→R1→P1→R2→...→Pn→R0 처럼 프로세스들이 원형으로 서로를 기다립니다.
4가지 조건 중 0/4 충족 — 데드락 위험 없음
정상
💡 해결책: (1) 순환 대기 제거 — 홀수 철학자는 오른쪽 먼저, 짝수는 왼쪽 먼저 집기. (2) 한 번에 두 포크 모두 집거나 아무것도 안 집기 (Hold & Wait 제거). (3) 철학자 수를 N-1명으로 제한 (동시 착석 제한).
08 — PROCESS vs THREAD

프로세스 vs 스레드

프로세스는 실행 중인 프로그램의 독립적인 인스턴스이고, 스레드는 프로세스 내에서 실행되는 가장 작은 실행 단위입니다.

프로세스 A
스레드 1
Stack · Registers · PC
스레드 2
Stack · Registers · PC
공유 영역
Code Data Heap Files
프로세스 B (독립)
스레드 1 (Main)
Stack · Registers · PC
독립 메모리 공간
Code Data Heap Files
⚠ 프로세스 간 직접 메모리 접근 불가 → IPC 필요
항목 프로세스 스레드
메모리 독립된 메모리 공간 같은 프로세스 메모리 공유
생성 비용 높음 (fork/exec) 낮음 (경량)
통신 방법 IPC (파이프, 소켓, 공유메모리) 공유 변수 직접 접근
격리성 높음 (하나 죽어도 영향 없음) 낮음 (하나 오류 → 전체 영향)
컨텍스트 스위칭 느림 (TLB flush 등) 빠름 (메모리 공유)
동기화 불필요 (독립) 필요! (Race condition 주의)
fork() / exec() 동작
멀티스레딩: 하나의 프로세스에서 여러 스레드가 동시에 실행. CPU 코어를 최대 활용하지만 Race Condition에 주의 필요. Chrome은 탭마다 별도 프로세스(안정성↑), Node.js는 단일 스레드 + 이벤트 루프.
09 — SYNCHRONIZATION

동기화 — Race Condition & 뮤텍스/세마포어

여러 스레드가 같은 자원을 동시에 접근할 때 발생하는 문제와 해결 방법입니다. 임계구역(Critical Section)을 보호하는 것이 핵심입니다.

① Race Condition
두 스레드가 공유 변수 counter를 동시에 증가시킬 때, 예상과 다른 결과가 나올 수 있습니다.
Thread 1
-
대기
공유 Counter
0
기대값: -
Thread 2
-
대기
② 뮤텍스 vs 세마포어
Mutex (상호배제)
· 값: 0 또는 1 (이진 잠금)
· 소유자가 lock/unlock
· 한 번에 1개 스레드만 진입
· 사용: 임계구역 보호
Semaphore (세마포어)
· 값: 0~N (정수 카운터)
· 여러 스레드가 사용 가능
· wait(P) / signal(V) 연산
· 사용: 자원 개수 제한
|
임계구역 (Critical Section): 공유 자원에 접근하는 코드 구간. 보호를 위해 상호배제(Mutex), 세마포어, 모니터 사용. 교착상태(Deadlock)를 피하려면 락 획득 순서를 일관되게 유지해야 합니다.