운영체제는 평소엔 존재감이 없다가, 막상 뭔가 느려지거나 멈추면 그제야 의식하게 되는 소프트웨어다. 지금 이 글을 띄우고 있는 순간에도 운영체제는 수백 개의 프로세스에 CPU 시간을 잘게 쪼개 나눠주고, 메모리가 부족하면 일부를 디스크로 밀어내고, 키보드 입력을 받아 화면에 글자를 그리는 일을 1초에도 수없이 반복하고 있다. 이 글에서는 "운영체제란 대체 무슨 일을 하는 소프트웨어인가"라는 큰 그림을 잡아본다. 세부 기능으로 들어가기 전에 이 지도를 손에 쥐고 있으면, 복잡해 보이는 기능들이 사실 몇 개의 일관된 목적에서 갈라져 나온 것임을 알 수 있다.
1. 소프트웨어와 운영체제
컴퓨터에서 돌아가는 소프트웨어는 목적에 따라 크게 둘로 나뉜다.
- 시스템 소프트웨어: 하드웨어를 직접 제어·운영하기 위한 프로그램. 운영체제(OS)가 대표적이고, 그 외에 소스 코드를 기계어로 번역하는 컴파일러·어셈블러, 여러 목적 파일을 하나로 묶는 링커(Linker), 그렇게 만들어진 실행 파일을 메모리에 올리는 로더(Loader) 등이 여기 속한다.
- 응용 소프트웨어: 사용자가 특정 목적을 위해 쓰는 프로그램. 엑셀·파워포인트 같은 사무용 도구, 포토샵 같은 그래픽 소프트웨어가 해당한다.
여기서 한 번쯤 짚고 넘어갈 만한 건 컴파일러나 링커 같은 개발 도구의 위치다. "내가 직접 실행하는 프로그램"이라는 감각 때문에 응용 소프트웨어처럼 느껴지지만, 이들은 결국 하드웨어가 이해할 수 있는 형태로 프로그램을 만들어내기 위한 시스템 지원 도구다. 즉 분류의 기준은 "누가 실행하느냐"가 아니라 "무엇을 위해 존재하느냐"에 있다.
컴퓨터 하드웨어와 사용자 사이에서 매개체(interface) 역할을 하는 시스템 소프트웨어. 사용자가 하드웨어의 복잡한 내부 동작을 몰라도 컴퓨터를 쓸 수 있게 추상화해주고, 동시에 CPU·메모리·디스크 같은 한정된 자원을 여러 프로그램에 효율적으로 할당·제어한다.
이 정의를 외우는 것보다 중요한 건, 운영체제의 일을 추상화(abstraction)와 자원 관리(resource management)라는 두 축으로 보는 시선이다. 추상화는 "디스크의 몇 번 섹터에 어떤 비트를 쓰는가"라는 물리적 디테일을 '파일'이라는 깔끔한 개념으로 가려주는 일이고, 자원 관리는 "한정된 CPU를 지금 누구에게 얼마나 줄 것인가"를 끊임없이 결정하는 일이다. 앞으로 살펴볼 모든 기능은 결국 이 두 축이 구체적인 상황에서 어떻게 나타나는가에 대한 이야기다.
2. 운영체제의 역할과 기능
운영체제는 한정된 자원을 여러 프로세스와 사용자에게 나눠주기 위해 다섯 가지 관리 기능을 수행한다.
| 관리 영역 | 핵심 역할 |
|---|---|
| 프로세스 관리 | 프로세스의 생성·상태 전이·제어, 스레드 스케줄링, 동기화, 교착상태(Deadlock) 처리 |
| 메모리 관리 | 주기억장치의 어느 영역이 어떤 프로세스에 쓰이는지 추적, 공간 할당·회수 |
| 보조기억장치 관리 | 디스크 빈 공간 관리, 저장 위치 배정, 디스크 스케줄링으로 I/O 최적화 |
| 장치 관리 | 장치 드라이버 인터페이스 제공, 버퍼링으로 CPU–장치 간 속도차 완화 |
| 파일 관리 | 파일·디렉터리 생성/삭제, 논리적 파일을 물리적 저장 매체에 매핑 |
이 다섯 가지를 따로따로 외우면 금방 잊는다. 대신 프로그램 하나가 실행되는 흐름을 따라가 보면 자연스럽게 엮인다. 프로그램을 더블클릭하면, 로더가 실행 파일을 읽어 오려고 파일 관리가 동작하고, 그 내용을 올릴 공간을 메모리 관리가 확보하며, 실행이 시작되면 프로세스 관리가 CPU 시간을 배분하고, 그 프로그램이 파일을 저장하거나 출력할 때마다 장치·보조기억장치 관리가 끼어든다. 운영체제가 처음에 어렵게 느껴지는 건 각 기능이 독립적으로 보여서인데, 사실 이들은 이렇게 한 흐름 안에서 끊임없이 협력한다.
3. 운영체제의 목적
운영체제를 설계하는 두 가지 큰 목적은 사용자의 편리성과 자원 활용의 효율성이다. 흥미로운 건 이 둘이 종종 정면으로 충돌한다는 점이다. 사용자가 즉각적인 반응을 느끼려면 CPU를 자주 빼앗아 여러 작업에 잘게 나눠줘야 하는데, 그렇게 자주 전환하면 문맥 교환(context switch) 비용이 쌓여 전체 처리량은 오히려 떨어진다. 운영체제 설계의 거의 모든 결정은 이런 trade-off를 어디서 타협할 것인가의 문제이고, 그 타협을 평가하는 잣대가 아래 성능 기준이다.
| 기준 | 설명 | 방향 |
|---|---|---|
| 처리능력 (Throughput) | 단위 시간당 처리하는 작업량 | 높을수록 좋음 ↑ |
| 반환시간 (Turnaround Time) | 작업 의뢰 시점부터 결과를 받을 때까지 걸린 총 시간 | 짧을수록 좋음 ↓ |
| 신뢰도 (Reliability) | 고장·실패 없이 기능을 정확히 수행하는 능력 | 높을수록 좋음 ↑ |
| 사용가능도 (Availability) | 필요할 때 자원을 얼마나 신속히 지원받는지 | 높을수록 좋음 ↑ |
네 기준을 같은 방향으로 뭉뚱그리지 않는 게 좋다. 처리능력·신뢰도·사용가능도는 "클수록 좋은" 양적 지표지만, 반환시간은 줄여야 하는 지표다. 그리고 처리능력과 반환시간은 앞서 말한 trade-off 때문에 동시에 최적화하기 어렵다. 한 작업을 끝까지 붙잡고 처리하면 그 작업의 반환시간은 짧아지지만 다른 작업들은 한없이 밀린다. 이 상충 관계는 CPU를 누구에게 먼저 줄지 정하는 문제에서 특히 두드러진다.
4. 운영체제의 발달
운영체제의 역사는 한마디로 "비싼 CPU를 어떻게 놀리지 않을 것인가"의 역사다. 초창기 컴퓨터는 한 대 값이 어마어마했기 때문에, CPU가 느린 입출력 장치를 기다리며 멈춰 있는 시간 자체가 곧 손실이었다. 아래 발전 단계는 전부 이 유휴 시간을 줄이려는 시도로 읽으면 흐름이 한눈에 들어온다.
No-OS → 상주 모니터 → 버퍼링·스풀링 → 다중 프로그래밍
- 버퍼링 (Buffering): 주기억장치 일부를 버퍼로 써서, 빠른 CPU와 느린 I/O 장치의 속도 차를 완충한다. CPU가 다음에 쓸 데이터를 미리 버퍼에 채워두고 계산을 이어가는 식. 다만 하나의 작업 내부에서만 겹치기가 일어난다는 한계가 있다.
- 스풀링 (Spooling): 디스크의 일부를 임시 저장소(Spool)로 사용한다. 버퍼링이 메모리를 썼다면 스풀링은 용량이 큰 디스크를 쓴다는 점, 그리고 여러 작업의 I/O를 동시에 대기시킬 수 있다는 점이 결정적 차이다. 프린터 스풀링이 대표적이다. 출력 명령을 내리면 문서가 곧장 디스크 스풀에 쌓이고, 우리는 인쇄가 끝나길 기다리지 않고 다른 일을 이어갈 수 있다.
- 다중 프로그래밍 (Multi-programming): 메모리에 여러 프로그램을 올려두고, 실행 중인 프로그램이 I/O 때문에 대기 상태가 되면 즉시 다른 프로그램에 CPU를 넘긴다. 앞의 두 기법이 "CPU와 장치를 겹쳐 돌리는" 수준이었다면, 다중 프로그래밍은 "여러 프로그램을 번갈아 돌려" CPU 활용도를 본격적으로 끌어올린 전환점이다. 이후의 시분할·스케줄링 개념이 모두 여기서 출발한다.
5. 운영체제의 분류·유형
운영체제는 작업 처리 방식·동시 사용자 수 등으로 나눌 수 있다.
① 작업 처리 방식 (발달 과정 순)
| 세대 | 방식 | 특징과 예시 |
|---|---|---|
| 1세대 | 일괄처리 (Batch) | 작업을 일정량 모아 한꺼번에 처리. 응답성은 없지만 단순·효율적. 예) 급여 계산, 전기요금 결산 |
| 2~3세대 | 다중 프로그래밍 | 여러 프로그램을 메모리에 올려 CPU 유휴 시간 최소화 |
| 2~3세대 | 다중 처리 (Multi-processing) | CPU를 2개 이상 두고 작업을 분담 |
| 2~3세대 | 시분할 (Time Sharing) | CPU 시간을 잘게 쪼개(Time Slice) 사용자에게 번갈아 할당. 각 사용자는 컴퓨터를 독점하는 듯 느낀다 |
| 2~3세대 | 실시간 (Real-time) | 정해진 시간 안에 반드시 결과를 산출. 예) 미사일 제어, 공장 자동화 |
| 4세대 | 분산처리 (Distributed) | 통신망으로 연결된 여러 컴퓨터를 하나의 시스템처럼 사용 |
이 표에서 곱씹어볼 만한 지점은 다중 프로그래밍과 시분할의 차이다. 둘 다 여러 프로그램을 번갈아 돌리는 건 똑같은데, CPU를 넘기는 기준이 다르다. 다중 프로그래밍은 실행 중인 작업이 I/O로 대기에 들어갈 때 비로소 CPU를 넘긴다 — 목표가 CPU를 놀리지 않는 것이기 때문이다. 반면 시분할은 정해진 시간 조각이 끝나면 그 작업이 아직 일하는 중이라도 강제로 CPU를 빼앗는다 — 목표가 모든 사용자에게 고른 응답성을 주는 것이기 때문이다. 시분할에서 각 사용자가 "내가 컴퓨터를 독점한다"고 느끼는 건 이 강제 전환을 사람이 눈치채지 못할 만큼 짧은 주기로 반복하기 때문이다. 우리가 지금 쓰는 데스크톱·노트북 운영체제의 직접적인 뿌리가 바로 이 시분할 방식이다.
② 그 외 분류
- 동시 사용자 수: 단일 사용자 / 다중 사용자
- 작업 처리 수: 단일 작업(Single-tasking) / 다중 작업(Multi-tasking)
6. 운영체제의 구성
운영체제 소프트웨어는 메모리 상주 여부와 역할에 따라 둘로 나뉜다.
- 커널 (Kernel): 운영체제의 핵심. 부팅 시 주기억장치에 적재되어 항상 상주하며, 자원 할당·하드웨어 제어처럼 가장 핵심적이고 빈번한 일을 직접 담당한다. '핵', '관리자 프로그램', '제어 프로그램'으로도 불린다.
- 유틸리티 (Utility): 평소엔 디스크에 비상주로 있다가 사용자가 요청할 때만 메모리에 올라와 실행되는 서비스 프로그램. 파일 관리 도구, 사용자 인터페이스 기능 등이 해당한다.
커널을 굳이 따로 떼어 상주시키는 데에는 분명한 이유가 있다. 모든 자원 요청은 결국 커널을 거치는데, 이렇게 자주 호출되는 코드를 매번 디스크에서 불러온다면 그 자체가 거대한 병목이 된다. 반대로 어쩌다 한 번 쓰는 유틸리티까지 전부 상주시키면 귀한 메모리가 낭비된다. "자주 쓰는 핵심만 메모리에 두고 나머지는 필요할 때 올린다"는 발상은, 자주 쓰는 데이터를 빠른 곳에 두는 캐시의 원리와도 정확히 같은 직관 위에 서 있다. 운영체제 곳곳에서 반복해 만나게 될 사고방식이다.
한 걸음 더
- 커널의 설계 철학도 여러 갈래다. 위에서 말한 "핵심을 한데 모은 커널"은 사실 모놀리식 커널(monolithic kernel)*의 모습이고, 리눅스가 대표적이다. 반대로 커널을 최소한으로 줄이고 파일 시스템·드라이버 같은 기능은 사용자 영역의 별도 프로세스로 빼는 *마이크로커널(microkernel) 설계도 있다(예: 미닉스, QNX). 안정성과 성능 사이의 trade-off가 커널 구조 선택에서도 그대로 재현된다.
- 우리가 흔히 "운영체제"라 부르는 윈도우·macOS·우분투에는 사실 커널 위에 셸·GUI·기본 유틸리티까지 잔뜩 얹혀 있다. 엄밀히 따지면 커널이 운영체제의 심장이고, 나머지는 그 심장을 감싼 사용자 편의 계층이다. "리눅스"가 엄밀히는 커널 이름이고 배포판이 그 위의 묶음을 가리킨다는 사실도 이 구분에서 나온다.
- 임베디드·실시간 분야로 가면 위 분류가 더 선명해진다. 미사일 제어나 자동차 ECU처럼 "마감 시간을 넘기면 결과가 무의미해지는" 영역에서는 평균 성능보다 최악의 응답 시간 보장이 전부라, 범용 운영체제와는 설계 우선순위 자체가 다르다.