운영체제 1편

운영체제란 무엇인가 — 로딩, 인터럽트, 직접 메모리 접근

suhyun·2026년 9월 23일·읽는 데 약 10분
한 줄로: 운영체제는 사용자와 하드웨어 사이의 중개자로서 자원을 가상으로 바꿔 나눠 주고, 신호에 반응하는 방식으로 움직입니다.

1. 프로그램은 스스로 뜨지 않는다

컴퓨터에서 프로그램을 하나 실행한다고 해 봅니다. 아이콘을 두 번 누르면 창이 뜹니다. 그 사이에 디스크에 있던 파일이 메모리로 올라가고, 프로세서가 그 명령어를 하나씩 읽어 실행합니다. 그런데 이 과정을 프로그램이 스스로 한 것은 아닙니다. 자기를 메모리에 올릴 수는 없기 때문입니다. 그 일을 대신해 주는 프로그램이 따로 있습니다. 그것이 운영체제입니다. 이 글에서는 운영체제가 무엇이고 어떤 방식으로 일하는지 봅니다.

2. 프로그램과 데이터는 같은 메모리에 있다

지금 쓰는 컴퓨터는 폰노이만 구조를 따릅니다. 핵심은 한 문장입니다. 프로그램과 데이터를 같은 메모리에 함께 저장합니다. 프로세서는 메모리에서 명령어를 하나 가져와 해석하고 실행한 뒤 다음 명령어를 가져옵니다. 이 과정을 계속 반복합니다. 메모리에 있는 것은 명령어든 데이터든 전부 숫자입니다. 둘을 가르는 것은 프로세서가 그 자리를 무엇으로 읽느냐뿐입니다.

3. 소스 코드에서 메모리까지

실행 파일 만들기

우리가 쓰는 것은 소스 코드입니다. 사람이 읽는 글자라서 그대로는 실행되지 않습니다. 컴파일러가 이것을 기계어로 바꾸고, 그 결과를 목적 파일이라고 합니다. 목적 파일 하나만으로는 아직 부족합니다. 화면에 출력하는 기능처럼 남이 만들어 둔 코드를 가져다 쓰기 때문입니다. 이 코드들을 하나로 묶어 주는 프로그램이 링커입니다. 링커가 묶고 나면 비로소 실행 파일이 됩니다.

로딩의 여섯 단계

실행 파일을 메모리로 올리는 일을 로딩이라고 합니다.

  1. 파일 앞부분의 머리말을 읽어 각 영역이 얼마나 큰지 알아냅니다.
  2. 그 크기에 맞춰 주소 공간을 만듭니다. 주소 공간은 이 프로그램이 쓸 수 있는 메모리 번지의 범위입니다.
  3. 코드와 초기값이 있는 데이터를 메모리에 복사합니다.
  4. 프로그램에 넘겨 줄 값인 인자를 스택에 올립니다. 스택은 함수가 잠시 쓰고 버리는 값을 쌓아 두는 영역입니다.
  5. 레지스터를 초기 상태로 맞춥니다. 레지스터는 프로세서 안에 있는 아주 작고 빠른 저장 칸입니다.
  6. 프로세서가 시작 지점으로 옮겨 갑니다.

이 여섯 단계가 끝나야 프로그램이 돌기 시작합니다.

4. 운영체제의 정의

방금 본 여섯 단계를 해 주는 것이 운영체제입니다. 정의는 이렇습니다. 운영체제는 하드웨어와 소프트웨어 자원을 관리하고 프로그램들에 공통 서비스를 제공하는 시스템 소프트웨어입니다. 두 가지로 나눠 보면 쉽습니다.

  • 사용자와 하드웨어 사이에 선 중개자입니다.
  • 커널과 그 주변 프로그램으로 이루어져 있습니다. 커널은 운영체제의 핵심이고 항상 메모리에 올라가 돌고 있는 부분입니다. 우리가 설치해 쓰는 응용 프로그램은 여기에 포함되지 않습니다.

5. 자원을 가상으로 바꾼다

운영체제가 하는 일을 짧게 줄이면, 물리적인 자원을 가상의 형태로 바꾸는 것입니다. 물리적인 자원은 프로세서 하나, 메모리 한 덩어리, 디스크 한 대입니다. 그런데 우리는 프로세서가 하나인데도 프로그램을 동시에 여러 개 띄웁니다. 운영체제가 프로세서를 아주 짧은 시간 단위로 잘라 프로그램들에 번갈아 주기 때문입니다. 메모리도 같은 방식으로 나눠 줍니다. 그 결과 각 프로그램은 프로세서와 메모리를 혼자 통째로 쓰고 있다고 여기게 됩니다. 자원을 시간과 공간으로 나눠 공유시키는 것, 이것이 운영체제의 일입니다.

6. 하드웨어와 속도 차이

운영체제가 관리하는 하드웨어는 프로세서와 주기억장치, 그리고 디스크와 키보드와 화면 같은 입출력 장치입니다. 이들은 버스라는 통로로 이어져 있고, 장치마다 그 장치를 맡아 제어하는 컨트롤러가 붙어 있습니다. 장치마다 다루는 방법이 제각각인데, 그 차이를 감추고 커널에 같은 모양으로 보이게 하는 코드가 장치 드라이버입니다.

여기서 문제가 하나 생깁니다. 프로세서는 아주 빠르고 입출력 장치는 아주 느립니다. 디스크에서 값을 하나 읽는 동안 프로세서는 수백만 번의 연산을 할 수 있습니다. 프로세서가 그동안 기다리기만 하면 그 시간이 전부 낭비입니다.

7. 인터럽트

주의를 요청하는 신호

그 낭비를 없애는 방법이 인터럽트입니다. 인터럽트는 지금 처리할 일이 생겼다고 알리는 신호입니다. 하드웨어도 보내고 소프트웨어도 보냅니다. 신호의 종류마다 번호가 붙어 있고, 각 번호에는 그것을 처리하는 코드인 인터럽트 처리기가 따로 준비되어 있습니다. 신호 번호를 주면 처리기의 위치를 알려 주는 표를 인터럽트 벡터라고 합니다. 운영체제는 이 신호를 기다렸다가 반응하는 방식으로 돕니다. 그래서 운영체제를 신호로 움직이는 프로그램이라고 부릅니다.

처리하는 세 단계

  1. 지금 하던 일의 상태를 저장합니다. 레지스터의 값과 다음에 실행할 명령어의 주소를 적어 둡니다. 이것을 남기지 않으면 돌아올 자리를 잃습니다.
  2. 인터럽트 벡터에서 그 번호에 맞는 처리기를 찾아 실행합니다.
  3. 저장해 둔 상태를 그대로 되돌리고 멈췄던 자리로 돌아갑니다.

중단된 프로그램에는 아무 일도 없었던 것처럼 보입니다. 중간에 다른 일을 하고 왔다는 사실을 알지 못합니다.

8. 하드웨어 인터럽트와 트랩

신호를 일으킨 쪽이 어디냐에 따라 이름이 갈립니다.

  • 하드웨어 인터럽트 — 프로세서 바깥의 장치가 보냅니다. 입출력이 끝났다는 신호나 일정 시간마다 울리는 타이머 신호가 여기에 해당합니다. 지금 돌고 있는 프로그램과 상관없이 아무 때나 옵니다. 지금 하는 일과 시점이 맞물려 있지 않다는 뜻에서 비동기라고 부릅니다.
  • 트랩 — 지금 실행 중인 그 명령어가 원인이 되어 그 자리에서 일어납니다. 시점이 맞물려 있으니 동기입니다. 트랩 안에는 두 종류가 있습니다. 예외는 영으로 나누거나 허용되지 않은 메모리를 건드리는 것처럼 잘못된 상황에서 일어납니다. 시스템 콜은 프로그램이 운영체제에 일을 부탁하려고 일부러 일으키는 신호입니다.

문제 1

프로그램이 파일을 읽으려고 운영체제에 요청을 보냈습니다. 이때 일어나는 신호는 하드웨어 인터럽트입니까, 트랩입니까. 그렇게 판단한 근거는 무엇입니까.

풀이

답은 트랩입니다. 근거는 신호가 일어난 시점입니다. 파일을 읽어 달라는 요청은 프로그램이 그 자리에서 일부러 일으킨 것이지, 바깥 장치가 아무 때나 보낸 것이 아닙니다. 지금 실행 중인 명령어가 원인이고 시점이 맞물려 있으니 동기이고, 그래서 트랩입니다. 더 좁히면 트랩 중에서도 시스템 콜입니다. 잘못된 상황이 아니라 프로그램이 의도해서 일으켰기 때문입니다. 반대로 읽기가 다 끝났다고 디스크가 알려 오는 신호는 바깥 장치가 보낸 것이므로 하드웨어 인터럽트입니다.

9. 인터럽트 구동 입출력

요청은 트랩이고 완료 통지는 인터럽트입니다. 이 완료 통지가 실제로 어떻게 쓰이는지 봅니다. 프로세서가 디스크에 읽기를 요청합니다. 요청만 보내고 기다리지 않고 바로 다른 일을 합니다. 디스크가 데이터를 다 준비하면 그때 인터럽트를 보냅니다. 프로세서는 하던 일을 잠시 멈추고 도착한 데이터를 가져간 뒤 원래 일로 돌아갑니다. 앞에서 본 낭비가 사라졌습니다. 프로세서가 멈추는 것은 실제로 데이터를 옮기는 그 짧은 순간뿐입니다. 이 방식을 인터럽트 구동 입출력이라고 부릅니다.

남는 문제는 데이터가 많을 때입니다. 한 번에 전송할 수 있는 양에는 한계가 있어서 큰 덩어리는 조각으로 나눠 보냅니다. 조각 하나가 도착할 때마다 인터럽트가 오고 프로세서가 그때마다 끼어듭니다. 기다리는 시간은 없앴는데 전송 자체는 그대로 프로세서의 몫으로 남은 것입니다.

10. 직접 메모리 접근(DMA)

그래서 옮기는 일만 전담하는 컨트롤러를 따로 둡니다. 이 방식을 직접 메모리 접근이라고 하고 영어 약자로 DMA라고 씁니다.

  1. 운영체제가 컨트롤러에 전송을 요청합니다. 어디서 어디로 얼마나 옮기라는 지시입니다.
  2. 컨트롤러가 프로세서를 거치지 않고 장치와 메모리 사이에서 직접 데이터를 옮깁니다. 이 동안 프로세서는 다른 일을 합니다.
  3. 전송이 다 끝나면 컨트롤러가 프로세서에 인터럽트를 한 번 보내 알립니다.

프로세서가 끼어드는 것은 이 마지막 한 번뿐입니다.

문제 2

디스크에서 1MB(1024KB)를 읽어 온다고 해 봅시다. 한 번에 옮기는 조각의 크기는 4KB입니다. 인터럽트 구동 입출력과 직접 메모리 접근에서 프로세서가 각각 몇 번 끼어듭니까.

풀이

먼저 조각이 몇 개인지 셉니다. 1024를 4로 나누면 256개입니다. 인터럽트만 쓰는 방식에서는 조각 하나를 옮길 때마다 인터럽트가 오니 프로세서가 256번 끼어듭니다. 직접 메모리 접근에서는 컨트롤러가 256개를 혼자 다 옮기고 끝났을 때 한 번만 알립니다. 끼어드는 횟수는 한 번입니다. 옮길 덩어리가 클수록 이 차이는 더 벌어집니다.

11. 계층과 캐싱

프로세서와 디스크의 속도 차이를 메우는 방법이 계층입니다. 프로세서 안에 가장 빠르고 가장 작은 캐시가 있고, 그 바깥에 주기억장치, 더 바깥에 디스크가 있습니다. 위로 갈수록 빠르고 비싸고 작습니다. 층 사이에서 하는 일이 캐싱입니다. 느린 쪽의 정보를 빠른 쪽에 복사해 두는 것입니다.

이것이 통하는 이유는 지역성 때문입니다. 방금 쓴 것을 곧 다시 쓰는 성질이 시간 지역성이고, 방금 쓴 것 근처를 곧 쓰는 성질이 공간 지역성입니다. 이 성질 덕분에 일부만 복사해 두어도 대부분 맞아떨어집니다.

정리

운영체제는 사용자와 하드웨어 사이의 중개자이고, 항상 돌고 있는 부분이 커널입니다. 하는 일은 자원을 가상으로 바꿔 나눠 주는 것이고, 움직이는 방식은 신호에 반응하는 것입니다. 바깥 장치가 보내면 하드웨어 인터럽트이고 지금 실행 중인 명령어가 일으키면 트랩입니다. 프로그램이 운영체제에 일을 부탁하는 시스템 콜은 트랩 쪽입니다. 큰 데이터는 전담 컨트롤러에 맡겨 프로세서를 놓아 줍니다.

시스템 콜은 아직 이름만 보고 지나갔습니다. 프로그램이 이 통로로 무엇을 부탁할 수 있는지, 운영체제가 그 요청을 어떻게 나눠 처리하는지는 다음 글에서 봅니다.

dev-news학습 노트소개개인정보 처리