1. 운영체제가 왜 중요한가?
운영체제(Operating System, OS)는 흔히 “하드웨어와 사용자(또는 응용 프로그램) 사이의 중간 계층”이라고 말한다.
하지만 전공생 입장에서 이 정의만으로는 너무 부족하다. 운영체제는 사실상 현대 컴퓨터 시스템의 규칙과 질서를 만드는 핵심 소프트웨어다.
1-1. OS가 없다면 어떤일이 생길까?
운영체제가 없다면, 개발자는 다음과 같은 일을 직접 해야한다.
- 프로그램마다 메모리 어느 영역을 쓸지 직접 계산해서 할당/해제
- CPU가 어떤 프로그램을 언제 실행할지 직접 결정
- 키보드, 마우스, 디스크, 네트워크 카드 등의 레지스터를 직접 조작
- 디스크의 어느 섹터를 쓸지 직접 관리
- 여러 프로그램이 동시에 실행될 때 충돌(경쟁 상태 등…) 해결
즉, 하드웨어의 모든 세부사항을 직접 제어해야 한다.
이는 사람이 직접 전선 하나하나를 납땜하며 회를 구성하는 것과 비슷한 수준의 고통이다.
운영체제는 이 복잡한 것들을 대신 처리해 주면서, 우리가 사용하는 상위 레벨의 언어(C, Java, Python 등)가 편하게 돌아갈 수 있는 환경을 제공한다.
1-2. 개발자 입장에서 운영체제가 중요한 이유
- 성능 튜닝과 디버깅
- 서버 CPU 사용량 100%, 메모리 부족, 디스크 I/O 병목 → 다 OS 레벨 문제
- top, htop, ps 같은 명령어를 제대로 이해하려면 OS 개념이 필수!
- 동시성(Concurrency) / 병렬성(Parallelism) 이해
- 프로세스 vs 스레드, 컨텍스트 스위칭, 임계구역, 데드락 → 전부 OS의 핵심 주제
- 멀티코어 활용, 비동기 프로그래밍, 쓰레드 풀 구현에도 직결
- 메모리 구조 이해
- Stack/Heap, 가상 메모리, 페이지 폴트, 캐시 지역성 → 알고리즘 성능, 메모리 최적화에 직접 영향
- 시스템 프로그래밍, 네트워크 프로그래밍
- 파일 I/O, 소켓, 프로세스 생성, IPC(파이프, 공유 메모리 등)는 거의 다 시스템 콜로 구현
- 면접, 코테, 실무 전부에서 자주 나온다
- “프로세스와 스레드의 차이”, “컨텍스트 스위칭이 뭐냐”, “세마포어와 뮤텍스 차이”, “가상 메모리의 장점” 같은 질문은 거의 OS 단골 손님
2. 운영체제의 핵심 역할
운영체제의 역할을 크게 나누면 두 가지 키워드로 정리할 수 있다.
- 추상화(Abstraction)
- 자원 관리(Resource Management) + 보호(Protection)
2-1. 추상화 (Abstraction)
운영체제는 하드웨어를 “사용하기 편한 추상화”로 감싸준다.
- 디스크 → “파일”이라는 추상화
- 메모리 → “가상 주소 공간”이라는 추상화
- CPU → “프로세스/스레드”라는 실행 단위로 추상화
- 네트워크 장치 → “소켓”이라는 추상화
예를 들어, 디스크는 실제로는 섹터, 트랙, 블록 등으로 구성된 물리 장치인데, 우리는 단지:
int fd = open("data.txt", O_RDONLY);
read(fd, buf, 100);
이렇게 “파일”을 읽는 시스템 콜로만 접근한다. 디스크가 SSD인지 HDD인지, 어떤 블록 번호에 저장됐는지 신경 쓸 필요가 없다.
2-2. 자원 관리(Resource Management)
운영체제는 컴퓨터의 한정된 자원을 여러 프로그램이 공정하고 효율적으로 사용하도록 관리한다.
- 관리 대상 자원:
- CPU 시간
- 메모리 (RAM)
- 디스크/파일 시스템
- 네트워크 대역폭
- 입출력 장치 (프린터, 키보드, 마우스 등)
대표적인 기능들:
- 스케줄링(Scheduling)
- 어떤 프로세스/스레드에게 CPU를 언제, 얼마나 줄지 결정
- 예: FCFS, SJF, Round Robin, Priority Scheduling 등
- 메모리 할당/해제
- 각 프로세스에 얼마만큼의 메모리를 줄지, 어떤 페이지를 물리 메모리에 둘지 결정
- 페이지 교체 알고리즘 (LRU, FIFO, Clock 등)
2-3. 보호(Protection)와 보안(Security)
운영체제는 각 프로그램이 서로의 메모리나 자원에 함부로 접근하지 못하게 막는 역할도 한다.
- 한 프로세스가 다른 프로세스의 메모리를 덮어쓰면 큰 문제 → 메모리 보호 장치 + 커널 모드/사용자 모드 구조로 방지.
- 파일 접근 권한 (읽기/쓰기/실행 권한, 사용자/그룹/기타)
- 시스템 콜을 통한 제한된 인터페이스 제공
- → 직접 하드웨어 레지스터를 건드리지 못하게 막고, OS를 통해서만 자원 접근 허용.
3. 운영체제의 구조(Architecture)
운영체제 내부가 어떻게 설계되어 있는지에 따라 여러 구조로 나눌 수 있다.
3-1. 커널(Kernel)과 사용자 공간(User Space)
운영체제의 핵심은 커널(Kernel)이다.
- 커널 공간(Kernel Space)
- OS 핵심 코드가 실행되는 특권 영역.
- 메모리, I/O, 스케줄링 등 시스템 전체에 영향을 미치는 코드.
- 사용자 공간(User Space)
- 일반 응용 프로그램이 실행되는 영역.
- 직접 하드웨어에 접근할 수 없고, 시스템 콜을 통해서만 커널 기능 사용.
이 둘을 논리적으로 나누기 위해 모드 비트(mode bit)를 사용해서:
- 0: 커널 모드
- 1: 사용자 모드
- 같은 식으로 구분하는 개념을 도입한다(실제 값은 구현마다 다를 수 있지만 개념적으로 그렇다).
3-2. 모놀리식 커널(Monolithic Kernel)
- 하나의 거대한 커널 바이너리에 거의 모든 OS 기능이 들어 있는 구조.
- 예: 전통적 Unix, Linux
- 특징:
- 장점: 커널 안에서 함수 호출로 바로바로 이어지기 때문에 성능이 빠름
- 단점: 한 부분에 버그가 있으면 전체 커널이 크래시 날 수 있고, 유지보수가 어렵다.
3-3. 마이크로커널(Microkernel)
- 정말 “핵심 중의 핵심” 기능만 커널 안에 넣고, 나머지 기능(파일 시스템, 디바이스 드라이버, 네트워크 등)은 사용자 공간의 서버 프로세스로 뺀 구조.
- 예: Minix, 일부 상용 RTOS, microkernel 기반 설계들
- 장점:
- 커널이 작아져서 안정성 증가
- 특정 서버(예: 파일 시스템 서버)가 죽어도, 커널 전체가 죽지 않고 재시작 가능
- 단점:
- 커널 ↔ 사용자 공간 프로세스 간 메시지 전달(IPC)이 많아지면서 성능 오버헤드 발생
3-4. 하이브리드 커널(Hybrid Kernel)
- 모놀리식과 마이크로커널의 장점을 어느 정도 섞은 형태.
- 예: Windows NT 계열, macOS의 XNU
- 실제로는 “마이크로커널 철학을 어느 정도 따르지만, 성능을 위해 여러 기능을 커널에 넣는” 현실적인 타협 구조.
3-5. 계층형 구조(Layered OS)
- 운영체제를 여러 층으로 나눠, 각 계층이 바로 아래 계층의 서비스만 사용하도록 하는 구조.
- 하드웨어
- CPU 스케줄러 / 메모리 관리
- I/O 관리
- 파일 시스템
- UI/쉘 등
- 장점:
- 설계와 이해가 쉽고, 유지 보수에 유리
- 단점:
- 계층간 의존성이 강해 유연성이 떨어질 수 있고, 효율보다 구조의 깔끔함을 우선할 수 있음.
4. 운영체제의 핵심 컴포넌트
운영체제의 내부를 기능별로 나누면 보통 다음과 같이 볼 수 있다.
컴포넌트 역할
| 프로세스 관리자(Process Manager) | 프로세스/스레드 생성, 스케줄링, 종료, 동기화 |
| 스케줄러(Scheduler) | CPU 자원을 어떤 프로세스에게 어떻게 배분할지 결정 |
| 메모리 관리자(Memory Manager) | 가상 메모리, 페이지 테이블, 페이지 교체, 보호 |
| 파일 시스템(File System) | 파일/디렉토리 추상화, 디스크 블록 관리 |
| I/O 서브시스템(I/O Subsystem) | 장치 드라이버, 인터럽트 처리, 버퍼링, 캐싱 |
| 네트워크 스택(Network Stack) | TCP/IP 프로토콜 구현, 소켓 추상화 제공 |
| 시스템 콜 인터페이스(System Call Interface) | 사용자 프로그램 ↔ 커널의 진입 지점 |
| 보호/보안 서브시스템(Protection & Security) | 권한 체크, 접근 제어, 인증 등 |
조금 더 풀어서 보자.
4-1. 프로세스 관리자/스케줄러
- 프로세스 생성: fork(), execve() 계열 호출
- 프로세스 상태: ready, running, blocked, terminated 등
- 스케줄러:
- 선점(preemptive) vs 비선점(non-preemptive)
4-2. 메모리 관리자
- 가상 주소 공간: 각 프로세스는 0번 주소부터 시작하는 독립된 주소 공간을 가진 것처럼 보임
- 페이지: 보통 4KB 단위
- 페이지 테이블: 가상 주소 → 물리 주소 매핑 정보 저장
- 페이지 폴트(Page Fault): 해당 페이지가 메모리(RAM)에 없을 때 디스크에서 가져오는 이벤트
4-3. 파일 시스템
- 디렉토리 트리 구조
- Inode(리눅스/유닉스 파일 시스템): 파일의 메타데이터를 담는 구조체
4-4. I/O 서브시스템과 디바이스 드라이버
- I/O는 상대적으로 느린 장치(디스크, 네트워크 등)가 많아서, 인터럽트와 DMA로 효율적인 처리가 중요하다.
- 디바이스 드라이버: 하드웨어 종속적 코드를 OS에 연결해, 상위 계층에서는 통일된 인터페이스로 장치를 사용할 수 있게 해준다.
5. 시스템 콜(System Call)과 모드 비트(Mode Bit)
5-1. 시스템 콜이란?
시스템 콜(System Call)은 사용자 프로그램이 운영체제(커널)의 서비스를 요청하는 공식적인 인터페이스이다.
- 예시:
- open(), read(), write(), close() → 파일 I/O
- fork(), execve(), exit() → 프로세스 관리
- socket(), bind(), connect(), accept() → 네트워크
C 코드에서 read()를 호출하면, 실제로는 C 라이브러리(glibc 등)가 내부에서 시스템 콜 번호를 세팅하고, 특수 명령어(예: x86의 syscall, int 0x80)를 실행해서 커널 모드로 진입한다.
5-2. 왜 시스템 콜이 필요한가?
- 사용자 모드에서는 보안·안정성 때문에 직접 하드웨어에 접근 불가.
- 예를 들어, 사용자 프로그램이:
- 임의의 물리 메모리 주소에 write
- 임의의 I/O 포트에 write
- 이런 것들을 허용하면 다른 프로세스, OS 자체를 망가뜨릴 수 있다.
그래서 운영체제는 커널 모드에서만 자원에 대한 직접 접근을 허용하고, 사용자 프로그램은 시스템 콜이라는 “문”을 통해서만 요청을 전달하도록 강제한다.
5-3. 모드 비트(Mode Bit)와 사용자 모드 ↔ 커널 모드 전환
CPU는 보통 특권 수준(privilege level) 을 구분하는 하드웨어 메커니즘을 제공한다.
- 사용자 모드(User Mode): 제한된 명령만 실행 가능 (I/O 명령, 특정 제어 레지스터 접근 불가)
- 커널 모드(Kernel Mode): 시스템 전체를 제어할 수 있는 특권 명령 실행 가능
이걸 논리적으로 모드 비트(Mode Bit)라고 부른다.
시스템 콜이 호출되면:
- 사용자 모드에서 시스템 콜 라이브러리 호출
- 시스템 콜 번호를 특정 레지스터나 스택에 세팅
- syscall 같은 특수 인스트럭션 실행 → 트랩(trap) 발생
- CPU가 모드 비트를 사용자 모드 → 커널 모드로 변경
- 시스템 콜 핸들러(커널 함수)로 점프
- 커널이 작업 수행 (예: 파일 읽기, 소켓 연결 등)
- 반환 시, 다시 모드 비트를 커널 모드 → 사용자 모드로 변경하고, 사용자 코드로 복귀
5-4. 시스템 콜 호출 흐름 예제 (파일 읽기)
C 코드:
int fd = open("test.txt", O_RDONLY);
char buf[100];
int n = read(fd, buf, 100);
내부적으로는 대략 이렇게 동작한다고 생각하면 된다(개념적 흐름):
- open() 함수 호출 → glibc 내부에서 sys_open 시스템 콜 번호 설정
- syscall 인스트럭션 실행 → trap 발생, 커널 모드 진입
- 커널의 sys_open() 함수가 실행되며:
- 권한 체크 (파일 읽기 가능한지?)
- 파일 시스템에서 해당 파일 위치(inode) 검색
- 프로세스의 파일 디스크립터 테이블에 엔트리 생성
- 파일 디스크립터 번호(fd)를 리턴
- 다시 사용자 모드로 돌아와 C 코드에서 fd 값 사용
read()도 마찬가지로, 커널 모드에서 파일 내용을 메모리(커널 버퍼)에 읽어오고, 그 내용을 사용자 공간 버퍼 buf에 복사해준다.
6. 추가 설명들 + 예제
6-1. 예제 1: 프로세스 생성 흐름 (fork + exec)
Unix 계열에서 새로운 프로그램을 실행할 때는 보통:
- 부모 프로세스가 fork() 시스템 콜로 자신을 복제한다.
- 자식 프로세스는 execve() 계열 시스템 콜로 실행할 프로그램을 자신의 주소 공간에 로드한다.
간단한 예:
pid_t pid = fork();
if (pid == 0) {
// 자식 프로세스
execl("/bin/ls", "ls", "-l", NULL);
// execl이 성공하면 이 아래 코드는 실행되지 않음
} else {
// 부모 프로세스
wait(NULL); // 자식 종료 대기
}
이 안에서 실제로는:
- fork() 호출 → 시스템 콜 → 커널 모드 진입
- 부모의 PCB(Process Control Block), 페이지 테이블 등을 복사 또는 COW(Copy-On-Write) 방식으로 공유
- 자식이 execl() → execve() 시스템 콜 → 커널 모드
- 해당 실행 파일을 디스크에서 읽어와 자식 프로세스의 주소 공간에 매핑
- 기존 코드/데이터/스택 내용 교체
이 모든 과정에서 프로세스, 메모리, 파일 시스템, I/O 등 OS의 여러 컴포넌트가 협력하여 동작한다.
6-2. 예제 2: 컨텍스트 스위칭(Context Switching)
CPU는 한 순간에는 한 프로세스(또는 스레드)만 실행할 수 있다.
멀티태스킹을 구현하기 위해 OS는 컨텍스트 스위칭을 수행한다.
컨텍스트 = 레지스터 값, 프로그램 카운터(PC), 스택 포인터, 페이지 테이블 포인터 등 현재 실행 상태 전체.
컨텍스트 스위칭 흐름(개략):
- 프로세스 A가 실행 중
- 타이머 인터럽트 발생 (예: 1ms마다)
- CPU가 커널 모드로 전환, 인터럽트 핸들러 실행
- 커널이 현재 프로세스 A의 레지스터 상태를 PCB에 저장
- 스케줄러가 다음 실행할 프로세스 B 선택
- PCB에서 B의 레지스터 상태를 복원
- CPU가 B의 컨텍스트로 재개 → 마치 B가 연속 실행되는 것처럼 보임
이렇게 해서 여러 프로세스가 동시에 실행되는 것처럼 보이는 착시 효과를 만든다.
6-3. 예제 3: 단순한 OS 레벨 사고방식 정리
(1) “파일 저장”은 OS 입장에서 무엇인가?
사용자 관점:
“메모장 켜서 memo.txt에 내용 쓰고 저장 클릭했어.”
OS 관점:
- 애플리케이션이 write() 시스템 콜 호출
- 커널 모드 진입 → 파일 디스크립터와 inode 확인
- 페이지 캐시(page cache)에 데이터 기록
- 일정 시점에 디스크 스케줄러가 실제 디스크 블록에 기록
(2) “프로그램 실행”은 OS 입장에서 무엇인가?
사용자 관점:
“크롬 아이콘 더블클릭했어.”
OS/런처 관점:
- GUI 셸(또는 터미널)이 fork() + exec()를 통해 크롬 프로세스를 생성
- OS가 크롬 프로세스에 새로운 가상 주소 공간 할당
- 실행 파일을 메모리에 매핑, 초기 스택 설정
- 스케줄러가 CPU 시간 할당 → 크롬 코드가 실행 시작
7. 정리
이 글에서는 운영체제의 역할과 구조를 전공생 관점에서 비교적 깊게 다뤄봤다.
정리하면 운영체제는:
- 하드웨어 위에 올라가는 추상화 계층이자,
- 여러 프로그램이 동시에 동작할 수 있도록 돕는 자원 관리자이며,
- 시스템 전체의 안정성과 보안을 책임지는 보호자(guardian) 역할을 한다.
그리고 내부적으로는:
- 커널 / 사용자 공간
- 모놀리식 / 마이크로커널 / 하이브리드 구조
- 프로세스/스케줄러, 메모리 관리자, 파일 시스템, I/O, 네트워크, 시스템 콜 인터페이스
- 등으로 구성되어 복잡하게 맞물려 돌아간다.
오늘의 공부

'CS' 카테고리의 다른 글
| [CS-운영체제] 메모리 계층과 캐시 (0) | 2025.11.18 |
|---|---|
| [CS-운영체제] 컴퓨터의 요소 (1) | 2025.11.17 |