본문 바로가기

운영체제란 무엇인가

운영체제가 하드웨어의 복잡함을 감추는 추상화와, CPU, 메모리, 입출력 장치를 여러 프로그램이 함께 쓰게 하는 자원 관리라는 두 역할을 정리합니다. 사용 환경에 따라 좋은 운영체제의 기준이 어떻게 달라지는지, 운영체제가 없다면 어떤 문제가 생기는지, 개발자가 운영체제를 알아야 하는 이유를 살펴봅니다.

스마트폰에서 앱을 열 때도, 노트북에서 브라우저를 띄울 때도, 서버가 API 요청을 처리할 때도 그 아래에서는 하드웨어를 조율하는 소프트웨어가 동작합니다. 이 소프트웨어를 운영체제(operating system, OS)라고 합니다. 프로그래밍을 처음 배울 때는 변수와 함수, 라이브러리만으로 프로그램이 돌아가는 것처럼 보이지만, 서버가 새벽에 멈추거나 여러 스레드를 쓰는 코드에서 다시 일으키기 어려운 결함을 만나면 "내 코드 아래에서는 무슨 일이 일어나고 있을까?"라는 질문이 생깁니다. 운영체제를 공부하는 것은 그 질문에 답하는 과정이며, 이 글에서는 운영체제가 무엇이고 왜 필요한지, 개발자에게 어떤 의미가 있는지를 정리합니다. 뒤의 장에서 다룰 프로세스, 스레드, 메모리, 파일 시스템, 동기화는 모두 이 글에서 그리는 큰 그림 위에 세부를 채워 가는 내용입니다.

운영체제의 두 역할

운영체제는 하드웨어와 응용 프로그램 사이에서 둘을 이어 주는 소프트웨어입니다. 큰 식당의 지배인에 비유하면, 손님은 메뉴를 보고 주문만 하면 되고, 요리사와 냉장고와 창고를 누가 언제 쓸지는 지배인이 정합니다. 손님이 주방에 들어가 불을 켜지 않아도 되는 것처럼, 프로그래머도 디스크의 섹터 번호를 직접 지정하지 않아도 됩니다.

운영체제의 두 역할

API를 제공하면서 자원을 함께 쓰는 규칙도 적용합니다

하드웨어 세부사항을 감추는 추상화와 여러 프로그램의 자원을 조율하는 관리는 같은 OS의 서로 다른 역할입니다.

프로그램의 요청과 운영체제의 두 역할프로그램 A와 B의 서비스 요청 두 개가 운영체제로 들어갑니다. 한 운영체제 안에 추상화와 자원 관리·보호의 역할이 함께 있으며, CPU·메모리·I/O를 조율하는 세 경로로 이어집니다. 추상화와 자원 관리가 별도 운영체제 또는 순차 호출 두 번을 뜻하지 않습니다.관리 대상 자원프로그램 A파일 읽기프로그램 B음악 재생서비스 요청운영체제추상화 제공open() · socket()파일·통신 끝점으로 요청자원 관리CPU · 메모리 · I/O 조율권한·보호 검사를 함께 적용조율CPU메모리I/O
프로그램의 요청과 운영체제의 두 역할프로그램 A와 B의 서비스 요청 두 개가 운영체제로 들어갑니다. 한 운영체제 안에 추상화와 자원 관리·보호의 역할이 함께 있으며, CPU·메모리·I/O를 조율하는 세 경로로 이어집니다. 추상화와 자원 관리가 별도 운영체제 또는 순차 호출 두 번을 뜻하지 않습니다.관리 대상 자원프로그램 A파일 읽기프로그램 B음악 재생요청요청운영체제추상화 제공open() · socket()이름·핸들로 요청자원 관리CPU · 메모리 · I/O할당·실행·요청을 조율권한·보호 검사를 함께조율CPU메모리I/O

화살표는 앱의 서비스 요청과 OS의 자원 조율 경로입니다. 모든 요청이 물리 장치 I/O를 발생시키는 것은 아닙니다. 아래 두 역할 설명은 같은 OS를 서로 다른 관점에서 읽는 보조 설명입니다.

추상화 제공 · 무엇을 호출하는가

open() → 파일

socket() → 통신 끝점

응용 프로그램이 장치의 레지스터나 블록 배치를 직접 다루는 부담을 줄입니다.

자원 관리 · 어떻게 공유하는가

CPU: 실행할 작업과 실행 시간을 조율

메모리: 주소 공간·페이지의 할당과 보호

I/O: 장치 접근과 요청의 처리를 조율

접근 제어와 보호 검사는 두 역할에 걸쳐 적용됩니다. 파일 잠금은 참여 프로그램의 협력이 필요할 수 있고, 가상 메모리는 무한한 용량을 보장하지 않습니다. 라이브러리 함수가 모두 시스템 콜인 것은 아닙니다.

첫째 역할은 자원 관리자(resource manager)입니다. 운영체제는 CPU, 메모리, 디스크, 네트워크 같은 하드웨어 자원을 여러 프로그램이 나누어 쓰도록 관리합니다. CPU 하나를 여러 프로세스가 번갈아 쓰게 하고, 한정된 메모리를 프로세스마다 나누어 주며, 디스크에 접근하는 순서를 조율합니다. 이런 조율이 없다면 한 프로그램이 메모리를 독차지해 다른 프로그램이 실행조차 되지 못하거나, 두 프로그램이 같은 디스크 영역을 동시에 고쳐 데이터가 뒤섞일 수 있습니다.

자원 관리에서는 공정성(fairness)과 효율성(efficiency)의 균형이 늘 문제가 됩니다. 모든 프로그램에 똑같은 CPU 시간을 주면 공정하지만 급한 작업이 늦어질 수 있고, 효율만 좇으면 어떤 프로그램은 끝없이 기다리는 기아(starvation) 상태에 빠질 수 있습니다. 이 균형을 잡는 방법이 스케줄링, 메모리 관리, 입출력 관리의 중심 주제이며, 이 교재 전체에서 되풀이해 다룹니다.

둘째 역할은 추상화(abstraction)를 제공하는 것입니다. 운영체제는 하드웨어의 복잡한 세부를 감추고 단순한 개념을 제공합니다. 프로그래머가 디스크의 섹터를 계산하지 않고 open("file.txt")로 파일을 열 수 있는 것은 운영체제가 "파일"이라는 추상화를 제공하기 때문이고, 이더넷 프레임을 직접 조립하지 않고 socket()과 send()로 통신할 수 있는 것도 같은 이유입니다. 그림처럼 두 역할은 서로 다른 운영체제가 아니라 같은 운영체제 안에 함께 있으며, 프로그램의 요청 하나를 처리할 때도 추상화와 자원 관리, 권한 검사가 함께 적용됩니다.

표준 API와 이식성 있는 C 코드를 쓰면 하드웨어가 달라도 소스를 덜 고쳐도 됩니다. 다만 CPU가 달라지면 보통 다시 컴파일해야 하고, 운영체제의 API와 ABI, 자료형의 크기, 장치의 기능 차이까지 저절로 사라지지는 않습니다. ABI(application binary interface)는 컴파일된 프로그램이 운영체제나 라이브러리와 맞물리는 이진 수준의 규칙으로, 시스템 콜 번호나 인자를 넘기는 레지스터 같은 것을 정합니다. 그래도 이런 추상화 덕분에 수많은 소프트웨어가 하드웨어마다 새로 쓰이지 않고 쌓여 갈 수 있습니다.

사용자의 관점과 시스템의 관점

같은 운영체제라도 누가 보느냐에 따라 중요하게 여기는 것이 다릅니다. 사용자의 관점에서는 편리함과 응답성이 중요합니다. 데스크톱 운영체제는 마우스 클릭에 바로 반응하고 여러 앱을 함께 실행할 수 있어야 하며, 동영상을 보면서 코드 편집기를 열고 메시지를 받는 일이 끊김 없이 이루어지는 것처럼 보이는 것은 운영체제가 CPU 시간을 몇 밀리초 단위로 잘게 나누어 프로그램마다 나누어 주기 때문입니다. 스마트폰 운영체제에는 배터리라는 제약이 더해져, 터치에 빨리 반응하면서도 백그라운드 앱이 배터리를 지나치게 쓰지 않게 해야 합니다.

시스템의 관점에서는 자원을 잘 활용하는 것이 중요합니다. 서버 운영체제는 많은 요청을 안정적으로 처리하고 장애에서 빨리 회복해야 합니다. 다만 CPU 사용률만 보고 낭비인지 잘 조정된 것인지 판단하지 않고, 요청의 지연 시간, 처리량, 입출력 대기, 대기열의 길이, 장애에 대비한 여유 용량을 함께 봅니다. CPU가 늘 가득 차 있다면 갑자기 부하가 늘었을 때 대응할 여유가 없을 수 있기 때문입니다.

자동차의 전자 제어 장치나 의료 장비, 산업용 제어기에 쓰는 임베디드 운영체제에는 또 다른 기준이 적용됩니다. 제한된 메모리와 전력 안에서 정해진 시간 안에 작업을 반드시 끝내는 실시간성(real-time)이 가장 중요합니다. 에어백 제어기가 보통은 10밀리초 안에 동작하지만 가끔 100밀리초가 걸린다면 쓸 수 없으며, 언제나 마감 시각을 지켜야 합니다.

관점가장 중요한 목표예
데스크톱 사용자응답성, 편리함Windows, macOS
모바일 사용자응답성과 배터리 효율Android, iOS
서버 관리자처리량, 안정성서버용 Linux
임베디드 시스템실시간성, 적은 자원RTOS, VxWorks

그래서 좋은 운영체제의 기준은 쓰이는 환경마다 다르게 정해야 합니다.

운영체제가 없다면

운영체제의 가치는 운영체제가 없는 상황을 떠올리면 분명해집니다. 아래 네 상황은 각각 운영체제의 주요 기능 하나에 대응합니다.

첫째, CPU가 하나인 컴퓨터에서 프로그램 A를 실행하는 중에 프로그램 B도 실행하고 싶다고 합시다. 운영체제나 실행을 바꾸어 주는 별도의 코드가 없다면 A가 끝날 때까지 기다려야 합니다. 운영체제 없이 하드웨어 위에서 바로 도는 프로그램도 스스로 실행 순서를 바꾸는 코드를 넣을 수는 있지만, 그 일을 프로그램이 직접 맡아야 합니다. 운영체제는 두 프로그램을 빠르게 번갈아 실행해 동시에 도는 것처럼 보이게 하며, 이것이 5장에서 다룰 CPU 스케줄링의 문제입니다.

둘째, 메모리가 4GB인 컴퓨터에서 프로그램 A, B, C가 각각 2GB, 2GB, 1GB를 필요로 한다고 합시다. 운영체제가 없다면 누군가 메모리를 직접 나누고 각 프로그램이 자기 영역만 쓰는지 지켜보아야 하며, 한 프로그램의 결함이 다른 프로그램의 메모리를 덮어쓰면 모두 망가집니다. 운영체제는 프로그램마다 독립된 주소 공간을 주고, 설정에 따라 스왑이나 페이지 회수를 이용해 물리 메모리보다 큰 요구를 다루기도 합니다. 그렇다고 가상 메모리의 용량이 끝없는 것은 아니어서, 메모리가 모자라면 할당이 실패하거나 운영체제가 프로세스를 강제로 끝내기도 하며, 이 내용은 9장의 가상 메모리에서 다룹니다.

셋째, 두 프로그램이 같은 파일에 동시에 쓰려고 한다고 합시다. 운영체제가 없다면 A가 쓴 데이터 위에 B가 덮어써 파일이 뒤섞일 수 있습니다. 운영체제는 파일 잠금과 접근 제어 수단을 제공하지만, Linux에서 흔히 쓰는 권고 잠금(advisory lock)은 프로그램들이 같은 규칙을 따를 때만 효과가 있으므로, 동시에 쓰는 데이터가 저절로 안전해지는 것은 아닙니다. 잠금의 자세한 규칙은 flock 매뉴얼에서 확인할 수 있으며, 파일을 디스크 블록으로 배치하는 일은 10장의 파일 시스템이 맡습니다.

넷째, 프린터로 출력하려면 프린터 컨트롤러의 레지스터에 데이터를 한 바이트씩 써야 하는데, 어느 레지스터에 어떤 순서와 타이밍으로 써야 하는지는 프린터 모델마다 다릅니다. 운영체제가 없다면 모든 프로그래머가 모든 프린터의 사양을 알아야 합니다. 운영체제는 장치 드라이버(device driver)라는 계층을 두어 이 차이를 흡수하므로, 프로그래머는 write(fd, data, len) 같은 호출 하나로 출력을 요청할 수 있습니다.

정리하면 운영체제는 하드웨어의 복잡함을 가리고, 여러 프로그램이 자원을 안전하게 나누어 쓸 수 있게 합니다. 오늘날의 거대한 소프트웨어 생태계는 이 기반 위에서 만들어졌습니다.

운영체제를 이루는 부분

운영체제를 이루는 주요 부분은 이 교재의 장마다 자세히 다룹니다. 아래 표는 각 부분이 하는 일과 그 내용을 다루는 장을 정리한 것입니다.

구성 요소하는 일다루는 장
프로세스 관리프로그램의 실행 단위인 프로세스와 스레드를 만들고, 끝내고, 스케줄링하고, 동기화한다3–7장
메모리 관리물리 메모리를 가상 주소로 추상화하고, 페이징과 스와핑으로 한정된 메모리를 나누어 쓴다8–9장
파일 시스템디스크의 블록을 파일과 디렉터리로 추상화한다10장
입출력 관리키보드, 디스크, 네트워크 카드 같은 장치를 일관된 방식으로 다룬다11장
보호와 보안자원에 대한 접근을 제어하고 시스템을 공격으로부터 지킨다12장

이 부분들은 서로 떨어져 있지 않습니다. 프로세스를 만들면 메모리가 할당되고, 파일을 열면 입출력이 일어나며, 그 모든 과정에서 권한 검사가 이루어집니다. 그래서 주제를 하나씩 따로 이해하면서도, 전체가 어떻게 맞물려 돌아가는지를 함께 보아야 합니다.

개발자가 운영체제를 알아야 하는 이유

"프레임워크가 다 해 주는데 왜 운영체제를 알아야 하나요?"라는 질문은 자연스럽습니다. Python으로 웹 서버를 만들 때는 flask.run()만 부르면 되는데, CPU 스케줄링이나 페이지 테이블을 알아야 할 이유가 잘 보이지 않습니다. 하지만 개발을 하다 보면 프레임워크가 해결해 주지 못하는 문제가 반드시 찾아옵니다.

예를 들어 배포한 뒤 서버의 메모리 사용량이 서서히 늘어 사흘 뒤 OOM(out of memory) 킬러가 프로세스를 강제로 끝내고, 다시 시작해도 사흘 뒤 같은 일이 되풀이된다고 합시다. 이것이 메모리 누수인지, 정상적으로 커지는 캐시인지, 가비지 컬렉터의 문제인지 판단하려면 프로세스의 메모리 구조와 가상 메모리, 실제로 물리 메모리에 올라온 크기(RSS)와 예약된 가상 주소의 크기(VSZ)의 차이를 알아야 합니다. 또 여러 스레드를 쓰는 코드에서 결과가 가끔만 달라지고, 디버거로 멈추어 보면 재현되지 않는 결함은 실행 타이밍에 따라 결과가 달라지는 경쟁 조건(race condition)일 수 있습니다. 이런 결함은 원리를 모르면 의심조차 하기 어렵습니다.

성능 문제도 마찬가지입니다. CPU 사용률은 20%인데 응답이 느리다면, 입출력을 기다리고 있을 수도 있지만 잠금을 얻으려고 줄을 서 있거나, 요청이 대기열에 쌓여 있거나, 한 스레드가 병목일 수도 있습니다. top의 입출력 대기 비율, iostat의 디스크 통계, ss의 연결 상태를 서로 맞추어 보는 진단은 모두 운영체제의 개념 위에서 이루어집니다. Docker 컨테이너가 무엇을 격리하는지, 컨테이너 안의 root가 호스트에 영향을 줄 수 있는지, 메모리 제한을 넘으면 어떻게 되는지 같은 질문에 답하려면 네임스페이스와 cgroup도 알아야 합니다.

기술 면접에서 "프로세스와 스레드의 차이", "가상 메모리", "교착 상태의 네 가지 조건"이 자주 나오는 것도 이 때문입니다. 이런 질문은 용어를 외웠는지보다 시스템 수준에서 생각할 수 있는지를 봅니다. 프레임워크는 모든 것이 정상일 때는 충분하지만, 장애나 성능 문제, 보안 문제가 생기면 그 아래를 들여다볼 수밖에 없으며, 운영체제에 대한 지식이 그 아래를 볼 수 있게 해 줍니다.

운영체제의 종류

운영체제는 목적과 환경에 따라 여러 종류로 나뉩니다. 범용 운영체제(general-purpose OS)는 Windows, macOS, Linux처럼 다양한 응용 프로그램을 실행할 수 있는 운영체제로, 데스크톱과 서버에 모두 쓰입니다. 서버에는 Linux를, 데스크톱에는 Windows를 쓰는 경우가 많지만, 그렇다고 한 운영체제가 모든 작업에 가장 알맞다고 판단할 수는 없습니다.

모바일 운영체제는 Android와 iOS처럼 스마트폰과 태블릿에 맞춘 운영체제로, 터치 인터페이스, 배터리 관리, 앱 사이의 격리, 앱 서명과 샌드박스 같은 보안이 중요합니다. Android는 Linux 커널을 쓰고, iOS는 Mach와 BSD 등으로 이루어진 Darwin의 XNU 커널을 씁니다.

실시간 운영체제(real-time OS, RTOS)는 VxWorks, FreeRTOS, QNX처럼 정해진 시간 안에 작업을 반드시 끝내야 하는 환경을 위한 운영체제로, 자동차의 ABS, 항공기 제어, 의료 장비, 공장 로봇에 쓰입니다. 범용 운영체제가 응답성과 처리량과 공정성을 함께 조율한다면, 실시간 운영체제는 시간을 예측할 수 있게 제어하는 것을 중시합니다. 다만 마감 시각을 실제로 지키려면 운영체제를 고르는 것 말고도, 작업마다 가장 오래 걸리는 실행 시간과 전체 부하를 분석해야 합니다.

임베디드 운영체제는 메모리가 수 KB에서 수 MB, CPU가 수십 MHz 정도로 자원이 매우 적은 IoT 센서나 가전, 스마트워치를 위한 운영체제로, Zephyr 등이 있습니다. 이 교재는 주로 Linux를 중심으로 범용 운영체제를 다루지만, 여기서 배우는 프로세스, 메모리 관리, 스케줄링, 동기화의 원리는 모든 운영체제에 공통으로 쓰입니다.

정리

  • 운영체제는 하드웨어와 응용 프로그램 사이에서, 하드웨어의 세부를 감추는 추상화와 여러 프로그램이 자원을 나누어 쓰게 하는 자원 관리를 함께 맡습니다.
  • 자원 관리에서는 공정성과 효율성의 균형이 늘 문제가 되며, 효율만 좇으면 어떤 프로그램은 기아 상태에 빠질 수 있습니다.
  • 좋은 운영체제의 기준은 데스크톱, 모바일, 서버, 임베디드처럼 쓰이는 환경마다 다릅니다.
  • 운영체제는 프로세스 관리, 메모리 관리, 파일 시스템, 입출력 관리, 보호와 보안으로 이루어지며, 이 부분들은 서로 맞물려 동작합니다.
  • 장애, 성능 문제, 보안 문제를 진단하려면 프레임워크 아래에서 운영체제가 하는 일을 알아야 합니다.

연습 문제

1. 같은 파일 읽기에서 두 역할 찾기

보고서를 읽는 프로그램 A와 음악을 재생하는 프로그램 B가 함께 실행되고 있습니다. A가 파일 이름만으로 내용을 읽을 수 있는 것과, A와 B가 CPU와 메모리를 나누어 쓰는 것은 각각 운영체제의 어떤 역할인지 설명하세요.

해설 보기

A가 디스크의 섹터를 몰라도 파일 이름으로 내용을 읽을 수 있는 것은 운영체제가 파일이라는 추상화를 제공하기 때문입니다. A와 B 가운데 누가 언제 CPU를 받을지, 각자 어느 메모리 영역을 쓸 수 있는지 정하는 것은 자원 관리와 보호의 역할입니다. 두 역할은 서로 다른 운영체제를 차례로 부르는 것이 아니라, 같은 운영체제 안에서 요청 하나를 처리할 때 함께 적용됩니다.

2. 편리한 API와 실행 순서

CPU가 하나인 컴퓨터에서 A는 파일 읽기를 기다리고 있고, B는 바로 실행할 수 있는 상태입니다. A가 쓰는 파일 API가 편리하다는 사실만으로 B가 언제 CPU를 받을지 알 수 있을까요?

해설 보기

알 수 없습니다. 파일 API는 요청하는 방법을 추상화할 뿐이고, 누구에게 언제 CPU를 줄지는 스케줄러가 정합니다. A가 입출력을 기다리는 동안 운영체제가 B에게 CPU를 넘길 수 있다는 것과, 특정한 시각에 반드시 넘긴다는 것은 다릅니다. 실제 순서는 스케줄링 정책과 다른 프로세스의 상태에 따라 달라지며, 이는 5장에서 다룹니다.

3. CPU 사용률 20%의 의미

서버의 CPU 사용률이 20%인데 응답이 느립니다. 동료가 "CPU가 한가한데 느리니 메모리 누수가 틀림없다"고 했습니다. 이 결론을 평가하세요.

해설 보기

CPU 사용률 하나만으로 메모리 누수라고 결론 낼 수는 없습니다. CPU가 한가한데 느리다면 입출력을 기다리거나, 잠금을 얻으려고 기다리거나, 요청이 대기열에 쌓여 있거나, 한 스레드에 일이 몰렸을 가능성도 있습니다. 입출력 대기 비율, 잠금 경합, 대기열의 길이, 시간에 따른 메모리 사용량의 변화를 각각 확인해 원인의 후보를 좁혀 가야 합니다.

다음 글 운영체제의 역사와 발전에서는 운영체제가 어떻게 발전해 왔는지 따라가며, 지금의 핵심 개념들이 어떤 문제를 풀려고 생겨났는지 살펴봅니다.