Skip to main content
Summary

운영체제는 프로그램의 실행 환경이다

개발자가 작성한 코드는 혼자 실행되지 않는다. CPU를 쓰고, 메모리를 할당받고, 파일을 열고, 네트워크로 데이터를 보내려면 반드시 운영체제의 도움을 받는다. 운영체제는 하드웨어와 애플리케이션 사이에 있는 중재자다. 프로그램이 하드웨어를 직접 다루지 않아도 실행될 수 있도록 공통된 규칙과 인터페이스를 제공한다.

예를 들어 웹 서버는 요청을 처리하면서 CPU에서 코드를 실행하고, 메모리에 객체를 만들고, 로그 파일에 기록하고, 데이터베이스와 네트워크 통신을 한다. 겉으로는 하나의 애플리케이션처럼 보이지만, 실제로는 운영체제가 CPU 시간, 메모리 공간, 디스크 접근, 네트워크 입출력을 계속 배분하고 있다.

이 원리를 이해하면 실무에서 만나는 문제가 조금 더 선명해진다. 프로세스가 왜 갑자기 종료되었는지, CPU 사용률이 왜 100%에 가까운지, 파일을 더 이상 열 수 없다는 에러가 왜 발생하는지 추적할 수 있다. 운영체제 지식은 시스템 장애를 낮은 계층에서 해석하게 해 주는 도구다.

운영체제의 역할과 프로세스 관리AI 생성 이미지

하드웨어 자원을 추상화한다

운영체제의 첫 번째 역할은 하드웨어 자원을 관리하는 것이다. 여기서 자원은 CPU, 메모리, 디스크, 네트워크 카드, 키보드, 모니터 같은 입출력 장치를 말한다. 애플리케이션이 이 장치들을 직접 제어하게 두면 문제가 많다. 여러 프로그램이 동시에 같은 메모리 영역을 덮어쓸 수도 있고, 하나의 프로그램이 디스크를 독점할 수도 있다.

운영체제는 이런 위험을 막기 위해 하드웨어를 추상화한다. 추상화란 복잡한 내부 동작을 감추고 사용하기 쉬운 형태로 제공하는 것이다. 개발자는 디스크의 물리적 섹터 위치를 직접 계산하지 않고 파일이라는 개념을 사용한다. 네트워크 카드의 전기 신호를 직접 다루지 않고 소켓이라는 인터페이스를 사용한다. 메모리 칩의 실제 주소를 직접 관리하지 않고 프로세스마다 독립된 주소 공간을 받은 것처럼 사용한다.

대표적인 추상화는 다음과 같다.

  • CPU는 프로세스와 스레드가 번갈아 사용하는 실행 자원으로 추상화된다.

  • 메모리는 각 프로세스가 독립적으로 사용하는 주소 공간으로 추상화된다.

  • 디스크는 파일과 디렉터리로 추상화된다.

  • 네트워크 통신은 소켓으로 추상화된다.

  • 장치는 파일, 핸들, 스트림 같은 일관된 인터페이스로 다뤄진다.

이 추상화 덕분에 애플리케이션 개발은 쉬워진다. 하지만 비용이 사라지는 것은 아니다. 파일을 여는 일은 운영체제 자원을 사용한다. 네트워크에 쓰는 일은 커널 버퍼와 장치 드라이버를 거친다. 메모리를 많이 요청하면 운영체제는 다른 프로세스와의 균형을 맞춰야 한다. 추상화 뒤에 실제 자원 경쟁이 있다는 점을 잊으면 성능 문제를 잘못 해석하기 쉽다.

프로세스는 실행 중인 프로그램이다

프로그램은 디스크에 저장된 실행 파일이다. 프로세스는 그 프로그램이 메모리에 올라와 실행 중인 상태다. 같은 실행 파일을 여러 번 실행하면 여러 개의 프로세스가 만들어질 수 있다. 예를 들어 같은 서버 애플리케이션을 두 개 실행하면 코드 파일은 같아도 프로세스 ID, 메모리 공간, 열린 파일 목록은 서로 다르다.

프로세스는 단순히 코드만 가진 존재가 아니다. 운영체제는 프로세스를 관리하기 위해 여러 정보를 함께 저장한다.

  • 프로세스 ID, 부모 프로세스 정보

  • 실행 중인 코드와 현재 실행 위치

  • 독립적인 메모리 주소 공간

  • 열린 파일과 소켓 목록

  • 권한 정보와 환경 변수

  • CPU 레지스터 값과 스케줄링 정보

이 정보는 운영체제가 프로세스를 멈췄다가 다시 실행하기 위해 필요하다. CPU는 한순간에 제한된 수의 실행 흐름만 처리할 수 있다. 하지만 사용자는 브라우저, 에디터, 터미널, 데이터베이스, 백그라운드 작업이 동시에 동작하는 것처럼 느낀다. 운영체제가 매우 짧은 시간 단위로 실행 대상을 바꾸기 때문이다.

실무에서 프로세스 개념은 자주 등장한다. 서버가 비정상 종료되면 운영체제나 실행 환경은 종료 코드와 시그널 정보를 남길 수 있다. 리눅스에서 kill 명령은 이름과 달리 항상 강제 종료만 뜻하지 않는다. 특정 프로세스에 시그널을 보내는 행위다. 정상 종료 요청일 수도 있고, 즉시 종료 명령일 수도 있다. 컨테이너 환경에서도 결국 컨테이너 안의 주 프로세스가 종료되면 컨테이너가 내려간다. 실행 단위를 프로세스로 이해해야 로그와 상태를 제대로 읽을 수 있다.

생성, 실행, 대기, 종료의 흐름

프로세스는 보통 몇 가지 상태를 오가며 생애주기를 가진다. 운영체제마다 이름은 조금씩 다르지만 핵심 흐름은 비슷하다.

새 프로세스가 만들어지면 먼저 준비 상태가 된다. 준비 상태는 실행할 수 있지만 아직 CPU를 받지 못한 상태다. 스케줄러가 이 프로세스에 CPU 시간을 배정하면 실행 상태가 된다. 실행 중 파일 읽기, 네트워크 응답 대기, 잠금 대기처럼 시간이 걸리는 작업을 만나면 대기 상태로 이동한다. 필요한 이벤트가 끝나면 다시 준비 상태가 되고, CPU를 받으면 실행을 이어 간다. 작업이 끝나거나 오류가 발생하면 종료 상태가 된다.

이 흐름은 성능 분석에서 중요하다. CPU 사용률이 낮은데 응답이 느리다면 프로세스가 CPU를 쓰지 못해서가 아니라 입출력 대기 상태에 오래 머무는 것일 수 있다. 반대로 CPU 사용률이 높은데 처리량이 늘지 않는다면 계산이 많거나, 너무 많은 실행 흐름이 CPU를 차지하려고 경쟁하는 상황일 수 있다.

프로세스가 대기 상태에 있는 것은 항상 나쁜 일이 아니다. 데이터베이스 응답을 기다리는 웹 서버 프로세스는 자연스럽게 대기할 수 있다. 문제는 대기가 예상보다 길거나, 대기 중인 프로세스가 너무 많거나, 특정 자원을 기다리느라 전체 시스템이 멈춘 것처럼 보일 때다. 장애 분석에서는 "프로세스가 살아 있는가"보다 "무엇을 기다리고 있는가"가 더 중요한 질문이 된다.

컨텍스트 스위칭은 공짜가 아니다

운영체제가 실행 중인 프로세스를 바꾸는 일을 컨텍스트 스위칭이라고 한다. 컨텍스트는 현재 실행을 이어 가기 위해 필요한 상태 정보다. CPU 레지스터, 프로그램 카운터, 스택 위치, 메모리 관리 정보 등이 포함된다. 운영체제는 현재 프로세스의 컨텍스트를 저장하고, 다음 프로세스의 컨텍스트를 복원한 뒤 실행을 넘긴다.

이 덕분에 여러 프로그램이 동시에 실행되는 것처럼 보인다. 하지만 컨텍스트 스위칭에는 비용이 있다. 상태를 저장하고 복원하는 시간도 필요하고, CPU 캐시에 있던 데이터가 새 프로세스에 맞지 않아 캐시 효율이 떨어질 수도 있다. 앞에서 살펴본 것처럼 CPU는 메모리 접근이 느려지면 연산 능력을 충분히 쓰지 못한다. 컨텍스트 스위칭이 잦아지면 실제 계산보다 실행 대상을 바꾸는 데 시간을 더 많이 쓰게 된다.

실무에서는 너무 많은 프로세스나 스레드를 만드는 설계가 이 비용을 키운다. 요청마다 무거운 프로세스를 새로 만들거나, 작업 수보다 훨씬 많은 실행 단위를 동시에 돌리면 처리량이 오히려 떨어질 수 있다. "동시에 많이 실행한다"는 말은 항상 "더 빠르다"와 같지 않다. CPU 코어 수, 작업의 성격, 입출력 대기 시간, 컨텍스트 스위칭 비용을 함께 봐야 한다.

시스템 콜은 사용자 프로그램과 커널의 경계다

일반 애플리케이션은 하드웨어를 직접 제어할 수 없다. 운영체제는 시스템 안정성을 위해 실행 영역을 나눈다. 애플리케이션이 실행되는 영역을 사용자 모드, 운영체제의 핵심 기능이 실행되는 영역을 커널 모드라고 한다. 커널 모드에서는 메모리 관리, 프로세스 제어, 장치 접근 같은 민감한 작업을 수행할 수 있다.

사용자 프로그램이 파일을 열거나, 네트워크로 데이터를 보내거나, 새 프로세스를 만들고 싶다면 커널에 요청해야 한다. 이 요청이 시스템 콜이다. 예를 들어 파일을 여는 open, 데이터를 읽는 read, 데이터를 쓰는 write, 프로세스를 복제하는 fork, 현재 프로세스의 실행 이미지를 다른 프로그램으로 바꾸는 exec 계열 기능은 운영체제의 도움 없이는 수행할 수 없다. 운영체제에 따라 이름과 방식은 다르지만, 애플리케이션이 민감한 자원에 접근할 때 커널을 거친다는 원리는 같다.

시스템 콜은 일반 함수 호출보다 무겁다. 사용자 모드에서 커널 모드로 전환해야 하고, 운영체제는 요청한 인자와 권한을 검사해야 하며, 실제 장치나 커널 자료구조를 다뤄야 한다. 그래서 작은 데이터를 아주 자주 파일에 쓰거나, 네트워크로 잘게 나누어 보내는 코드는 시스템 콜 횟수 때문에 느려질 수 있다. 버퍼링이 중요한 이유가 여기에 있다. 데이터를 모아 한 번에 쓰면 시스템 콜 횟수와 입출력 비용을 줄일 수 있다.

파일 핸들 고갈도 이 경계에서 이해할 수 있다. 프로그램에서 파일이나 소켓을 열면 운영체제는 이를 추적하기 위한 핸들 또는 파일 디스크립터를 할당한다. 사용 후 닫지 않으면 프로세스가 가진 핸들이 계속 증가한다. 결국 프로세스별 한도나 시스템 전체 한도에 도달하면 "too many open files" 같은 에러가 발생한다. 이는 단순한 코드 버그처럼 보이지만 실제로는 운영체제 자원을 반환하지 않은 문제다.

스케줄링은 무엇을 먼저 실행할지 정하는 정책이다

CPU를 원하는 프로세스는 많고 CPU 코어는 제한되어 있다. 운영체제의 스케줄러는 어떤 프로세스에 언제 CPU를 줄지 결정한다. 이 결정 방식이 스케줄링 정책이다. 좋은 정책의 기준은 하나가 아니다.

응답 시간을 중요하게 보면 사용자의 입력이나 짧은 요청에 빠르게 반응해야 한다. 데스크톱 환경이나 API 서버에서는 응답 시간이 중요하다. 처리량을 중요하게 보면 단위 시간 동안 얼마나 많은 작업을 끝냈는지가 핵심이다. 배치 처리나 대용량 계산 작업에서는 처리량이 중요할 수 있다. 공정성을 중요하게 보면 특정 프로세스가 CPU를 독점하지 못하게 해야 한다. 여러 사용자가 함께 쓰는 서버에서는 공정성이 중요하다.

이 세 목표는 자주 충돌한다. 짧은 작업을 먼저 실행하면 응답 시간은 좋아질 수 있지만 긴 작업은 계속 밀릴 수 있다. 모든 프로세스에 똑같이 CPU 시간을 나누면 공정해 보이지만, 중요한 실시간 작업의 응답성이 떨어질 수 있다. 처리량을 높이려고 문맥 교환을 줄이면 한 작업이 오래 CPU를 차지해 다른 작업의 대기 시간이 늘 수 있다.

개발자는 운영체제 스케줄러를 직접 구현하지는 않지만, 스케줄러가 잘 일할 수 있는 구조를 만들어야 한다. CPU를 오래 점유하는 작업은 요청 처리 경로에서 분리할 수 있다. 입출력 대기가 많은 작업은 비동기 처리나 작업 큐로 조절할 수 있다. 우선순위가 다른 작업을 같은 프로세스 풀에 섞으면 중요한 요청이 뒤로 밀릴 수 있다. 스케줄링은 운영체제 내부의 주제이면서 동시에 애플리케이션 구조의 문제다.

운영체제 관점으로 장애를 읽기

운영체제 지식은 추상적인 이론이 아니라 관찰 기준이다. 서버가 느릴 때 먼저 CPU가 바쁜지, 입출력을 기다리는지, 메모리가 부족한지, 프로세스 수가 비정상적으로 늘었는지, 파일 핸들이 고갈되었는지 확인해야 한다. 같은 "느림"도 원인은 다르다.

CPU 사용률이 높다면 알고리즘 비용, 무한 루프, 과도한 직렬화, 압축, 암호화, 정규식 처리 같은 CPU 중심 작업을 의심할 수 있다. CPU 사용률이 낮은데 요청이 쌓인다면 데이터베이스, 디스크, 네트워크, 잠금 대기처럼 외부 응답을 기다리는 상황일 수 있다. 프로세스가 자주 재시작된다면 메모리 초과, 치명적 예외, 운영체제 시그널, 헬스 체크 실패를 확인해야 한다. 파일 핸들 수가 계속 증가한다면 파일, 소켓, 파이프를 닫지 않는 누수를 찾아야 한다.

운영체제는 모든 프로그램 아래에서 자원을 배분한다. 개발자는 프레임워크 로그만 보지 말고, 필요할 때 운영체제의 관찰 지표까지 내려가야 한다. 프로세스 상태, CPU 사용률, 메모리 사용량, 열린 파일 수, 입출력 대기 시간은 코드와 시스템 사이를 연결하는 단서다.

이번 장의 핵심은 단순하다. 프로그램은 운영체제 위에서 실행된다. 운영체제는 자원을 추상화하고, 프로세스를 관리하며, 시스템 콜을 통해 안전한 경계를 제공하고, 스케줄링으로 제한된 CPU를 나눈다. 이 구조를 이해하면 장애를 볼 때 "코드가 느리다"에서 멈추지 않고 "어떤 자원을 기다리거나 과도하게 쓰고 있는가"까지 질문할 수 있다.

책 목록

개발자가 알아야 할 컴퓨터 과학 지식 정리

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기