Skip to content

Lecture 26. 운영체제

개요

핵심 질문

  • 운영체제는 프로세스·메모리·파일을 어떻게 관리하는가?
  • 프로세스와 스레드의 차이는 무엇이며 어떻게 동기화하는가?
  • 가상 메모리와 페이징은 어떻게 동작하는가?
  • AI 시스템 개발에서 운영체제 지식이 왜 필요한가?

학습 목표

  • 운영체제의 핵심 역할(CPU·메모리·파일 관리)을 설명할 수 있다.
  • 프로세스 상태 전이, 문맥 교환, 스레드 동기화 원리를 이해한다.
  • 가상 메모리·페이징·페이지 교체 알고리즘을 설명할 수 있다.
  • AI 개발자 관점에서 멀티프로세싱, 비동기 I/O, 메모리 관리의 의미를 이해한다.

핵심 개념

1. 운영체제 개요

운영체제의 역할

역할설명핵심 기술
CPU 관리프로세스에 CPU 할당 순서·시간 결정CPU 스케줄링
메모리 관리실제 물리 메모리보다 큰 메모리 제공가상 메모리, 페이징
파일 관리보조기억장치 정보를 파일·폴더로 접근파일 시스템
프로세스 관리실행 순서 제어, 자원 배분스케줄러, IPC

커널 (Kernel)

운영체제의 핵심 기능을 담당하는 부분. 시스템 자원에 직접 접근할 수 있는 특권 모드에서 실행된다.

이중 모드 (Dual Mode)

  • 사용자 모드: 사용자 응용 프로그램이 실행되는 모드 — 커널 자원 직접 접근 불가
  • 커널 모드: 운영체제 코드 실행 모드 — 하드웨어·메모리 직접 접근 가능

시스템 콜 (System Call)

사용자 모드 프로그램이 커널 서비스를 요청하는 인터페이스. 파일 읽기, 프로세스 생성, 메모리 할당 등.

사용자 프로그램 → 시스템 콜 호출 → 소프트웨어 인터럽트 발생
→ 커널 모드 전환 → 커널 코드 실행 → 사용자 모드 복귀

AI 개발자 관점: PyTorch DataLoader가 멀티프로세스로 데이터를 로드할 때, 파일 읽기·프로세스 생성·메모리 할당 모두 시스템 콜을 통해 이루어진다.


2. 프로세스

프로세스 메모리 구조

실행 중인 프로그램(프로세스)은 메모리에 다음 4개 영역으로 적재된다.

영역내용특징
코드(텍스트) 영역CPU가 실행할 명령어읽기 전용
데이터 영역전역 변수, 정적 변수 (초기값 있음)프로그램 종료까지 유지
BSS 영역전역 변수, 정적 변수 (초기값 없음)0으로 초기화
힙 영역동적 할당 메모리 (malloc, new)런타임 크기 결정
스택 영역지역 변수, 매개변수, 복귀 주소함수 호출마다 프레임 생성

힙은 낮은 주소 → 높은 주소 방향으로 성장, 스택은 높은 주소 → 낮은 주소 방향으로 성장.

PCB (Process Control Block)

운영체제가 프로세스를 관리하기 위해 커널 영역에 유지하는 자료구조.

포함 정보:

  • 프로세스 ID (PID)
  • 프로세스 상태
  • 레지스터 값 (PC, SP 등)
  • CPU 스케줄링 정보 (우선순위)
  • 메모리 관련 정보 (페이지 테이블 주소)
  • 열린 파일 목록

프로세스 상태 전이

생성(new) → 준비(ready) ⇄ 실행(running) → 종료(terminated)

                         대기(blocked)
  • 준비 → 실행: 디스패치 (CPU 할당)
  • 실행 → 준비: 타이머 인터럽트 (타임슬라이스 만료)
  • 실행 → 대기: I/O 요청, 자원 대기
  • 대기 → 준비: I/O 완료, 자원 획득

문맥 교환 (Context Switch)

실행 중인 프로세스를 교체하는 과정.

  1. 현재 프로세스의 문맥(레지스터 값, PC 등)을 PCB에 저장
  2. 다음 프로세스의 PCB에서 문맥 복구
  3. 새 프로세스 실행 재개

잦은 문맥 교환은 캐시 미스 증가와 CPU 오버헤드를 유발한다.

블로킹 vs 논블로킹 I/O

  • 블로킹 I/O: I/O 완료까지 프로세스가 대기 상태로 전환 — 단순하지만 CPU 낭비
  • 논블로킹 I/O: I/O를 맡기고 즉시 다음 명령어 실행 — 비동기, CPU 효율적

AI 개발자 심화 — 멀티프로세싱과 데이터 로딩

PyTorch DataLoader의 num_workers > 0은 별도 자식 프로세스를 생성하여 데이터 전처리를 병렬화한다.

  • 각 Worker 프로세스는 독립된 메모리 공간 보유 → 데이터 충돌 없음
  • fork() 시스템 콜로 부모 프로세스 복제 → 자식 프로세스 생성
  • 공유 메모리(/dev/shm)를 통해 메인 프로세스로 배치 전달 — 복사 오버헤드 감소
  • pin_memory=True: 페이지 고정 메모리 사용으로 GPU 전송 속도 향상

3. 스레드

프로세스 vs 스레드

프로세스스레드
메모리독립 (코드·데이터·힙·스택 전부)코드·데이터·힙 공유, 스택만 독립
생성 비용높음 (fork)낮음
통신IPC 필요 (느림)공유 메모리로 직접 통신 (빠름)
격리한 프로세스 오류가 다른 프로세스에 영향 적음한 스레드 오류가 전체 프로세스에 영향

스레드 안전 (Thread Safety)

멀티스레드 환경에서 동시 접근해도 결과가 항상 올바른 상태.

레이스 컨디션(Race Condition): 여러 스레드가 공유 자원을 동시에 접근하여 실행 순서에 따라 결과가 달라지는 문제.

임계 구역(Critical Section): 한 번에 하나의 스레드만 실행해야 하는 코드 영역.

AI 개발자 심화 — GIL (Global Interpreter Lock)

CPython(표준 Python)은 GIL로 인해 동일 프로세스 내에서 여러 스레드가 파이썬 코드를 동시에 실행할 수 없다.

  • I/O 바운드 작업: 스레드 유효 (GIL이 I/O 대기 중 해제됨)
  • CPU 바운드 작업: 멀티프로세싱 사용 (multiprocessing 모듈)
  • PyTorch DataLoader가 num_workers로 스레드 대신 프로세스를 사용하는 이유

4. 동기화와 교착 상태

동기화의 두 가지 목표

  1. 상호 배제: 임계 구역에 하나의 스레드/프로세스만 접근
  2. 실행 순서 제어: 특정 순서에 따라 자원 접근

뮤텍스 락 (Mutex Lock)

이진 잠금 도구. 임계 구역 진입 전 acquire(), 이후 release().

acquire(): 락이 없으면 기다림, 있으면 획득 후 진입
release(): 임계 구역 종료 후 락 반환

세마포 (Semaphore)

공유 자원이 여러 개인 경우의 동기화. 변수 SS = 가용 자원 수.

wait():SS1, S<0이면 대기 \text{wait}(): S \leftarrow S - 1,\ S < 0 \text{이면 대기}

signal():SS+1, 대기 프로세스 깨움 \text{signal}(): S \leftarrow S + 1,\ \text{대기 프로세스 깨움}

  • 이진 세마포 (S{0,1}S \in \{0,1\}): 뮤텍스와 유사
  • 카운팅 세마포: 여러 개의 동일 자원 관리

모니터 (Monitor)

공유 자원 + 접근 함수를 하나로 캡슐화한 동기화 도구. Java의 synchronized 키워드가 모니터 기반.

교착 상태 (Deadlock)

발생 4가지 필요 조건 (모두 충족 시 교착 상태 발생):

  1. 상호 배제: 자원을 한 번에 하나의 프로세스만 사용
  2. 점유와 대기: 자원을 점유한 채 다른 자원 대기
  3. 비선점: 강제로 자원을 빼앗을 수 없음
  4. 원형 대기: 프로세스들이 원형으로 자원 대기

해결 방법

방법전략특징
예방4가지 조건 중 하나 제거자원 효율 감소
회피안전 상태 유지 (은행원 알고리즘)사전에 자원 요구량 파악 필요
탐지 후 회복주기적 탐지 후 강제 종료 또는 자원 선점오버헤드 발생

5. CPU 스케줄링

스케줄링 기준 지표

  • CPU 활용률: 전체 시간 중 CPU가 일하는 비율
  • 처리율(Throughput): 단위 시간당 완료된 프로세스 수
  • 대기 시간: 준비 큐에서 기다린 시간
  • 반환 시간: 제출부터 완료까지의 전체 시간
  • 응답 시간: 요청 후 첫 응답까지의 시간

선점형 vs 비선점형

  • 선점형: 운영체제가 CPU를 강제 회수 가능 — 응답성 좋음, 문맥 교환 오버헤드
  • 비선점형: 프로세스가 자발적으로 반환할 때까지 대기 — 오버헤드 적음, 응답성 나쁨

주요 알고리즘

알고리즘방식특징
FCFS도착 순서단순, 호위 효과
SJF실행 시간 짧은 것 우선최적 대기 시간, 실행 시간 예측 어려움
Round Robin (RR)타임슬라이스 순환공평, 타임슬라이스 크기가 성능 결정
SRT잔여 시간 최소SJF의 선점형 버전
우선순위우선순위 높은 순아사 현상 → 에이징으로 해결
다단계 피드백 큐큐 간 이동 허용유연, 현대 OS의 기반

리눅스 CFS (Completely Fair Scheduler)

vruntime=실제 실행 시간×기준 가중치프로세스 가중치 \text{vruntime} = \text{실제 실행 시간} \times \frac{\text{기준 가중치}}{\text{프로세스 가중치}}

vruntime이 가장 작은 프로세스를 다음에 실행 — 우선순위 높을수록 가중치 높아 vruntime 느리게 증가 → 더 많은 CPU 시간 할당.

AI 개발자 심화

  • 학습 프로세스 우선순위: GPU 집약적 학습 프로세스에 높은 우선순위 부여 (nice 값 조정)
  • 실시간 추론 서버: SCHED_FIFO 또는 SCHED_RR 정책으로 응답 지연 최소화

6. 가상 메모리

물리 주소 vs 논리 주소

  • 물리 주소: 메모리 하드웨어의 실제 주소
  • 논리 주소: 프로세스별로 0부터 시작하는 가상 주소 공간

MMU (Memory Management Unit): CPU와 메모리 사이에서 논리 주소 → 물리 주소 변환.

스와핑 (Swapping)

메모리 부족 시 실행되지 않는 프로세스를 보조기억장치의 스왑 영역으로 내보내고(swap out), 필요 시 다시 메모리로 복귀(swap in).

페이징 (Paging)

논리 주소 공간을 고정 크기의 페이지(page) 로, 물리 주소 공간을 동일 크기의 프레임(frame) 으로 나누어 임의의 프레임에 페이지를 할당하는 방식.

  • 외부 단편화 없음 (고정 크기)
  • 내부 단편화 발생 가능 (마지막 페이지 일부 낭비)

페이지 테이블 (Page Table)

프로세스의 페이지 번호 → 물리 프레임 번호 매핑 테이블.

주요 PTE (Page Table Entry) 비트:

비트의미
유효 비트 (Valid)1: 메모리에 적재됨, 0: 스왑 영역에 있음
보호 비트 (Protection)읽기(r), 쓰기(w), 실행(x) 권한
참조 비트 (Reference)CPU가 해당 페이지 접근 여부
수정 비트 (Dirty)페이지 데이터 수정 여부 — 스왑 아웃 시 쓰기 필요 여부 판단

페이지 폴트 (Page Fault)

CPU가 접근한 페이지의 유효 비트가 0 — 보조기억장치에서 메모리로 로드 필요.

처리 과정:

  1. 페이지 폴트 발생 → 커널 모드 전환
  2. 페이지 폴트 처리 루틴 실행
  3. 보조기억장치에서 해당 페이지를 메모리로 적재
  4. 페이지 테이블 갱신 (유효 비트 1로)
  5. 중단된 명령어 재실행

TLB (Translation Lookaside Buffer)

페이지 테이블의 캐시 메모리. 최근 사용한 페이지 번호 → 프레임 번호 매핑 저장.

  • TLB 히트: TLB에서 바로 프레임 번호 획득 → 메모리 1회 접근
  • TLB 미스: 페이지 테이블 접근 필요 → 메모리 2회 접근

요구 페이징 (Demand Paging)

프로세스 시작 시 전체 페이지를 메모리에 올리지 않고, 실제 접근 시에만 페이지를 메모리에 로드하는 방식.

페이지 교체 알고리즘

메모리가 가득 찼을 때 내보낼 페이지를 선택하는 알고리즘.

알고리즘방식특징
FIFO가장 오래 있던 페이지 교체단순, 성능 불안정 (Belady의 역설)
최적 (OPT)앞으로 가장 오래 사용 안 될 페이지 교체최적이지만 미래 예측 불가 (이론적 기준)
LRU가장 오래 사용 안 된 페이지 교체실제 가장 많이 사용, 참조 비트 활용

다단계 페이지 테이블 (Multi-level Page Table)

페이지 테이블 자체를 페이지로 나누어 계층 구조로 관리 → 페이지 테이블의 메모리 사용량 감소.

AI 개발자 심화

  • VRAM OOM과 가상 메모리: GPU VRAM은 별도 메모리로 운영체제 페이징의 직접 대상이 아니다. VRAM 부족 시 torch.cuda.OutOfMemoryError 발생 — 페이지 교체가 아닌 수동 관리 필요.
  • Huge Pages: 기본 페이지 크기(4 KB) 대신 2 MB 또는 1 GB 페이지 사용 — TLB 히트율 향상, 대용량 모델 가중치 로딩에 유리.
  • 메모리 맵 파일(mmap): 파일을 가상 주소 공간에 직접 매핑 — 대용량 데이터셋을 메모리처럼 접근. HuggingFace의 대형 모델 가중치 로딩에 활용.
  • Copy-on-Write (CoW): fork() 시 자식 프로세스가 부모 메모리를 즉시 복사하지 않고 수정 시점에만 복사 — DataLoader 멀티프로세싱의 메모리 효율 기반.

7. 프로세스 간 통신 (IPC)

공유 메모리 (Shared Memory)

여러 프로세스가 동일한 메모리 영역을 공유 — 가장 빠른 IPC.

메시지 전달

커널을 통해 데이터를 주고받는 방식.

방식특징
파이프 (Pipe)단방향 통신, 부모-자식 프로세스 간
지명 파이프 (Named Pipe)양방향, 독립 프로세스 간 가능
시그널 (Signal)비동기 이벤트 알림 (SIGTERM, SIGKILL 등)
소켓 (Socket)네트워크 기반, 원격 프로세스 간 통신
RPC원격 함수 호출 — gRPC의 기반

AI 개발자 심화

  • DataLoader IPC: num_workers > 0인 DataLoader는 Worker 프로세스와 메인 프로세스 간에 공유 메모리(/dev/shm) 또는 소켓을 통해 배치 데이터를 주고받는다.
  • 분산 학습 프로세스 통신: torch.distributed는 NCCL(GPU), Gloo(CPU), MPI 백엔드를 통해 프로세스 간 그래디언트를 AllReduce한다.
  • 비동기 I/O: LLM 추론 서버(vLLM, TGI)는 비동기 I/O(asyncio)로 수백 개의 동시 요청을 처리하면서 GPU 연산을 블로킹하지 않는다.

8. 파일 시스템

핵심 개념

개념설명
블록운영체제가 파일을 읽고 쓰는 단위 (일반적으로 4 KB)
파일 디스크립터프로세스가 열린 파일을 식별하는 정수 (0: stdin, 1: stdout, 2: stderr)
아이노드 (inode)파일 메타데이터 + 데이터 블록 주소 저장
마운트다른 파일 시스템을 현재 트리에 연결

파일 할당 방식

  • 연속 할당: 연속된 블록에 저장 — 빠른 접근, 외부 단편화
  • 연결 할당: 각 블록이 다음 블록 주소 포함 — 유연, 순차 접근만 가능
  • 색인 할당: 색인 블록에 모든 블록 주소 저장 — 직접 접근 가능, Linux ext4의 기반

AI 개발자 심화

  • 대용량 학습 데이터 I/O: HDFS, NFS, S3와 같은 분산 파일 시스템을 마운트하여 로컬 파일 시스템처럼 접근.
  • 체크포인트 저장: 모델 체크포인트는 수 GB에 달하므로 파일 시스템 블록 크기, 버퍼링 방식이 저장 속도에 영향. torch.save()pickle + OS 파일 쓰기 시스템 콜.
  • /dev/shm: 리눅스의 RAM 기반 임시 파일 시스템 — 멀티프로세스 DataLoader의 배치 버퍼로 활용, 디스크 I/O 없이 메모리 속도로 공유.

수식 정리

CPU 활용률

CPU 활용률=CPU가 작업한 시간전체 시간×100% \text{CPU 활용률} = \frac{\text{CPU가 작업한 시간}}{\text{전체 시간}} \times 100\%

TLB를 고려한 유효 메모리 접근 시간 (EMAT)

EMAT=h×tTLB+(1h)(tTLB+tmem)+tmem \text{EMAT} = h \times t_{\text{TLB}} + (1-h)(t_{\text{TLB}} + t_{\text{mem}}) + t_{\text{mem}}

  • hh: TLB 적중률, tTLBt_{\text{TLB}}: TLB 접근 시간, tmemt_{\text{mem}}: 메모리 접근 시간

리눅스 CFS vruntime

vruntime+=Δt×기준 가중치프로세스 가중치 \text{vruntime} += \Delta t \times \frac{\text{기준 가중치}}{\text{프로세스 가중치}}

페이지 폴트율과 유효 접근 시간

EAT=(1p)×tmem+p×tpage fault \text{EAT} = (1-p) \times t_{\text{mem}} + p \times t_{\text{page fault}}

  • pp: 페이지 폴트율, tpage faultt_{\text{page fault}}: 페이지 폴트 처리 시간 (수ms ~ 수십ms)