1.시스템&인프라/개발 입문자를 위한 운영체제

2편. 프로세스란 무엇인가 – 프로그램이 살아 움직이는 방식의 이해

쿼드큐브 2025. 11. 14. 10:37
반응형
반응형

2편. 프로세스란 무엇인가 – 프로그램이 살아 움직이는 방식의 이해

 

📚 목차
1. 프로그램과 프로세스의 차이 - 코드와 실행의 경계
2. 프로세스 생명주기(Lifecycle)와 상태 전이
3. 프로세스 간 통신(IPC)의 개념과 방식
4. 실습으로 배우는 프로세스 모니터링(ps, top, 작업관리자)
5. 좀비(Zombie) 프로세스와 고아(Orphan) 프로세스 - 예외 상황과 대응 방법
✔ 마무리 - 프로세스를 이해해야 시스템을 통제 할 수 있습니다.

 

처음으로 리눅스 서버에 SSH 접속해 top 명령어를 실행했을 때, 예상보다 많은 프로세스들이 실행 중이라는 사실에 놀랐던 적이 있습니다. 단순히 하나의 프로그램을 실행했을 뿐인데 왜 이렇게 많은 실행 단위가 생겨날까? 이 궁금증은 운영체제의 핵심 개념인 '프로세스'로 이어집니다.


프로세스는 정적인 프로그램을 실제로 살아 움직이게 만드는 실행 단위입니다. 이 개념을 정확히 이해하면 시스템이 멀티태스킹을 어떻게 구현하는지, 왜 충돌이나 느려짐이 발생하는지, 그리고 개발자가 성능 최적화를 위해 어떤 부분을 고려해야 하는지를 명확히 알 수 있습니다.

 

1. 프로그램과 프로세스의 차이 – 코드와 실행의 경계

🔷 프로그램(Program)이란?

프로그램은 하드디스크나 SSD 같은 저장장치에 보관된 정적인 코드 집합입니다.

예를 들어 chrome.exe, python, notepad.exe와 같은 실행 파일들은 모두 프로그램에 해당합니다.

이들은 실행되기 전까지는 단지 데이터 파일일 뿐이며, 메모리나 CPU와 같은 시스템 자원을 전혀 사용하지 않습니다.

 

🔷 프로세스(Process)란?

프로세스는 프로그램이 실제로 실행되어 운영체제로부터 메모리, CPU 시간, 파일 핸들 등 시스템 자원을 할당받은 상태를 말합니다.

하나의 프로그램이 실행되면 하나의 프로세스가 생성되며, 경우에 따라 동일한 프로그램이 여러 번 실행되면서 여러 개의 프로세스가 동시에 존재할 수도 있습니다.

각 프로세스는 독립된 실행 흐름을 가지며, 시스템 내에서 고유한 프로세스 ID(PID)로 식별됩니다.

 

✔️비유

프로그램은 '레시피', 프로세스는 '조리 중인 음식'에 비유할 수 있습니다.
코드 자체는 정적이지만, 실행되는 순간 시스템 자원을 사용하는 '살아 있는 단위'가 됩니다.

 

✔️ 예시 설명

➤ Ubuntu 환경:

gedit 텍스트 편집기를 실행하면, 저장장치에 있던 gedit 프로그램이 메모리에 적재되고, 실행 가능한 프로세스로 전환됩니다.

이때 ps나 top 명령어를 통해 해당 프로세스를 확인할 수 있습니다.

 

➤ Windows 환경:

사용자가 chrome.exe를 두 번 실행하면, 백그라운드에서는 여러 개의 chrome.exe 프로세스가 생성됩니다.

이는 Chrome이 각 탭을 별도의 프로세스로 분리하여 처리하는 멀티프로세싱 구조를 채택하고 있기 때문입니다.

따라서 작업 관리자(Task Manager)에서는 수십 개의 Chrome 프로세스가 동시에 실행 중인 것을 볼 수 있습니다.

프로그램 vs 프로세스
프로그램 vs 프로세스

 

2. 프로세스 생명주기(Lifecycle)와 상태 전이

프로세스는 단순히 "시작 → 종료"의 직선적인 흐름으로 끝나는 것이 아닙니다.

운영체제는 각 프로세스를 상태별로 관리하며, 시스템 상황에 따라 다양한 상태로 전환시키는 과정을 거칩니다.

이를 프로세스의 생명주기라고 부르며, 이 개념은 운영체제의 핵심적인 역할 중 하나입니다.

 

🔷 주요 상태 설명

🔸Create/New (생성): 프로그램이 실행 요청을 받았지만, 아직 시스템 자원 할당이 완료되지 않아 실행 준비가 되지 않은 초기 상태입니다.

🔸Ready (준비): 프로세스가 실행 가능한 상태로 대기열에 들어가 있으며, CPU 스케줄러가 자원을 할당해 주기만을 기다리는 상태입니다.

🔸Running (실행 중): 프로세스가 실제로 CPU를 점유하여 명령을 수행하는 상태입니다. 단일 CPU 시스템에서는 오직 하나의 프로세스만 Running 상태가 됩니다.

🔸Waiting / Blocked (대기 중): 프로세스가 입출력(I/O)이나 특정 이벤트(예: 네트워크 응답, 사용자 입력 등)를 기다리는 상태로, CPU를 사용할 수 없습니다. 이 상태에서는 운영체제가 해당 이벤트가 발생할 때까지 프로세스를 일시 중지시킵니다.

🔸Terminated (종료됨): 프로세스의 실행이 끝나고, 운영체제에 의해 모든 자원이 회수된 상태입니다. 이 시점에서 프로세스는 더 이상 시스템에 존재하지 않습니다.

 

🔷 프로세스 상태 전이도

프로세스 상태 전이도
프로세스 상태 전이도

 

✔️ 예시 설명

➤ Ubuntu 예시:
터미널에서 sleep 10 명령어를 실행하면, 해당 프로세스는 10초 동안 아무 동작도 하지 않고 시간을 지연하게 됩니다.

이때는 명령어 자체가 실행된 직후 잠깐 Running 상태가 되었다가 곧바로 Waiting 상태로 진입하며, 10초 동안 CPU를 점유하지 않습니다.

운영체제는 그 사이 다른 프로세스에 CPU를 할당합니다.


➤ Windows 예시:
파일을 열거나 서버에 접속하는 프로그램이 네트워크 응답을 기다리는 상황에서는, 해당 프로세스가 입출력 완료를 기다리는 동안 Blocked(Waiting) 상태로 전환됩니다.

예를 들어, 파일 탐색기에서 네트워크 드라이브가 연결되지 않은 상태에서 폴더를 열려고 하면, 잠시 멈춰 있는 것처럼 보이는 이유가 바로 이 Waiting 상태 때문입니다.

 

✔️ 예시 시나리오 - 워드 프로세서 실행 중 프린터 사용
1. 시작: 사용자가 워드 프로세서 프로그램을 실행합니다. → New 상태로 전환됩니다.
2. 준비 완료: 워드 프로세스가 실행될 준비를 마치면 → Ready 상태가 되어 CPU 할당을 기다립니다.
3. 실행 중: 운영체제가 워드 프로세스에 CPU를 할당하면 → Running 상태가 되어 사용자가 문서를 작성할 수 있게 됩니다.
4. 대기 (I/O 발생): 사용자가 작성 중인 문서를 '프린터로 출력'하도록 요청합니다. 프린터 작업은 CPU가 아닌 외부 장치(I/O 장치)와 관련된 작업이므로, 워드 프로세스는 잠시 CPU를 반납하고 → Waiting 상태로 전환되어 프린터가 작업을 완료하기를 기다립니다. 이 동안 CPU는 다른 프로세스에게 할당될 수 있습니다.
5. 재개: 프린터 출력이 완료되면, 운영체제는 워드 프로세스를 다시 → Ready 상태로 만들어 CPU 할당을 기다리게 합니다.
6. 종료: 사용자가 워드 프로그램을 닫으면 → Running 상태에서 모든 작업을 마치고 → Terminated 상태로 전환됩니다.

 

3. 프로세스 간 통신(IPC)의 개념과 방식

현대의 운영체제는 수많은 프로세스가 동시에 실행되며 서로 협력하거나 정보를 주고받는 구조로 동작합니다.

웹 브라우저, 파일 탐색기, 백신 프로그램처럼 각각 독립적으로 보이는 프로그램들도 내부적으로는 여러 프로세스가 서로 정보를 교환하며 작동합니다.

이러한 협업을 가능하게 해주는 기능이 바로 IPC(Inter-Process Communication, 프로세스 간 통신)입니다.


운영체제는 여러 가지 IPC 메커니즘을 제공하여 프로세스 간 데이터 전달, 이벤트 알림, 동기화 등을 가능하게 합니다.

 

🔷 대표적인 IPC 방식
🔸 파이프(Pipe)

파이프는 한 프로세스의 출력 결과를 다른 프로세스의 입력으로 전달하는 방식의 통신입니다.

기본적으로 단방향(one-way)이며, 가장 단순한 형태의 IPC입니다.
쉘 명령어에서 | 기호로 자주 사용되며, 실제로는 두 개의 프로세스가 데이터를 파이프를 통해 주고받는 구조입니다.

예: ls | grep txt → ls의 출력이 grep의 입력으로 전달됨.

 

🔸소켓(Socket)

소켓은 네트워크를 기반으로 하는 양방향 통신 방식으로, 서로 다른 컴퓨터 간 또는 같은 컴퓨터 내의 프로세스 간에도 사용할 수 있습니다.
주로 클라이언트-서버 구조에서 사용되며, TCP/IP 같은 네트워크 프로토콜 위에서 동작합니다.

인터넷 브라우저와 웹 서버 간의 통신이 대표적인 예입니다. 또한 로컬에서 localhost 주소를 이용해 두 프로세스 간 통신도 가능합니다.

🔸메시지 큐(Message Queue)

메시지 큐는 프로세스 간에 메시지를 주고받기 위해 운영체제가 제공하는 큐(Queue)를 활용하는 방식입니다.
프로세스는 메시지를 큐에 넣고, 다른 프로세스는 그 메시지를 나중에 꺼내 사용합니다.

이 방식은 비동기(Asynchronous) 통신에 유용하며, 생산자-소비자 구조에 자주 사용됩니다.


🔸공유 메모리(Shared Memory)

공유 메모리는 두 개 이상의 프로세스가 동일한 메모리 공간을 함께 사용하는 방식입니다.
가장 빠른 IPC 방식 중 하나이며, 대용량 데이터를 주고받을 때 효과적입니다.

하지만 동시에 접근하면 충돌이 발생할 수 있기 때문에, 보통 세마포어(semaphore), 뮤텍스(mutex) 같은 동기화(synchronization) 도구와 함께 사용됩니다.

 

✔️ 프로세스간 통신 구조 예

프로세스 A ──(파이프/소켓/공유 메모리 등)──▶ 프로세스 B

왼쪽의 프로세스 A가 데이터를 생성하고, 이를 운영체제가 제공하는 IPC 메커니즘(예: 파이프, 소켓, 공유 메모리 등)을 통해 오른쪽의 프로세스 B에 전달합니다.

중간에는 커널 공간이 개입하여 자원을 안전하게 관리하며, 통신의 방향성과 구조는 사용 목적에 따라 달라질 수 있습니다.

 

✔️ 예시 설명

➤ Ubuntu – 파이프를 활용한 간단한 IPC

ls | grep py

위 명령은 ls 프로세스가 출력한 내용을 파이프(|)를 통해 grep 프로세스로 전달하는 구조입니다.

두 프로세스는 독립적이지만, 운영체제가 중간에서 파이프를 생성하여 데이터를 전달함으로써 통신이 이루어집니다.

이는 매우 기본적이면서도 강력한 IPC 형태입니다.
이 구조는 쉘 스크립트나 시스템 자동화에서 매우 자주 사용됩니다.

 

➤ Windows – COM 객체를 통한 프로세스 협업

Windows에서는 COM(Component Object Model) 기반의 객체를 활용해 여러 응용 프로그램이나 프로세스가 데이터를 공유합니다.


예를 들어, Excel에서 여러 창을 띄웠을 때 각각이 독립된 프로세스처럼 보이지만, 실제로는 백그라운드에서 COM 객체를 통해 서로 통신하며 하나의 문서를 동시에 편집하지 않도록 조율합니다. 이는 Windows 운영체제가 제공하는 고급 IPC 메커니즘의 일환입니다.


대규모 오피스 소프트웨어, CAD 도구, 금융 프로그램 등이 이 방식을 활용해 상호작용합니다.

반응형

 

4. 실습으로 배우는 프로세스 모니터링

운영체제는 현재 실행 중인 수많은 프로세스를 관리합니다. 사용자는 이를 확인하고, 필요에 따라 특정 프로세스를 종료하거나 상태를 점검할 수 있어야 합니다.

리눅스(Ubuntu)에서는 ps, top 명령어를 통해, 윈도우에서는 작업 관리자(Task Manager)를 통해 이를 확인할 수 있습니다.

 

🔷 Ubuntu – 터미널에서 실시간 프로세스 보기

Ubuntu에서는 터미널을 이용해 다양한 방식으로 프로세스를 확인할 수 있습니다. 가장 기본이 되는 명령어는 ps와 top입니다.

✔️ ps aux로 모든 프로세스 조회하기

ps aux | grep firefox

이 명령어는 현재 실행 중인 모든 프로세스를 출력한 후, 그 중에서 firefox라는 문자열이 포함된 프로세스만 보여줍니다.
▸ ps : 프로세스 상태(Process Status)를 출력하는 명령어입니다.
▸ a : 다른 사용자의 프로세스도 함께 표시
▸ u : 사용자 이름과 메모리 사용량 등 상세 정보 표시
▸ x : 터미널에 연결되지 않은 데몬 프로세스도 포함

 

➤ 출력 예시

원하는 프로그램이 정말 실행되고 있는지 확인할 때 매우 유용합니다.

ubuntu   10125  4.1  5.2 2362480 428800 ?  Sl   10:11   0:45 /usr/lib/firefox/firefox

▸ 10125: 프로세스 ID (PID)
▸ 4.1: CPU 사용률
▸ 5.2: 메모리 사용률
▸ /usr/lib/firefox/firefox: 실행 중인 프로그램 경로

 

✔️ top 명령어로 실시간 모니터링

top

top은 실행 중인 모든 프로세스 정보를 실시간으로 갱신해서 보여줍니다. CPU, 메모리, 프로세스 수 등 시스템 자원을 한눈에 파악할 수 있습니다.

top 실행 예시
top 실행 예시

 

시스템이 느려졌을 때 top을 실행해서 CPU를 과도하게 사용하는 프로세스를 식별하고, k 키로 종료할 수 있습니다.

 

🔷 Windows 실습 – 작업 관리자로 프로세스 확인하기

Windows에서는 GUI 환경에서 손쉽게 프로세스를 확인할 수 있도록 작업 관리자(Task Manager)를 제공합니다.

작업 관리자를 실행하는 방법은 두 가지가 있습니다.
먼저, Ctrl + Shift + Esc 단축키를 사용하면 바로 작업 관리자가 실행됩니다.
또는, Ctrl + Alt + Del 키를 누른 후 나타나는 옵션 화면에서 "작업 관리자" 항목을 선택해도 동일한 결과를 얻을 수 있습니다.

작업관리자로 프로세스 확인하기
작업관리자로 프로세스 확인하기

➤ 출력 예시

Whale가 여러 개 실행 중이라면, 탭별로 분리된 프로세스임을 알 수 있습니다.

어떤 프로세스가 시스템을 과도하게 사용 중이면, 해당 프로세스를 마우스 우클릭 → "작업 끝내기"로 종료할 수 있습니다.

 

5. 좀비 프로세스와 고아 프로세스 – 예외 상황과 대응 방법

운영체제에서는 모든 프로세스가 항상 깔끔하게 종료되지는 않습니다.

때때로 부모-자식 관계의 종료 시점이 어긋나거나 비정상적인 상황이 발생하면서, 관리되지 않는 프로세스가 시스템에 남게 됩니다.

 

대표적인 경우가 바로 좀비 프로세스(Zombie Process)와 고아 프로세스(Orphan Process)입니다.

 

🔷 좀비 프로세스(Zombie Process)

좀비 프로세스는 이름처럼 이미 죽었지만 시스템에 남아 있는 프로세스입니다.

정확히 말하면, 프로세스 자체는 종료되었지만 그 종료 상태(exit status)를 부모 프로세스가 아직 수거하지 않은 상태입니다.

 

UNIX 계열 운영체제에서는 자식 프로세스가 종료되면 부모가 wait() 또는 waitpid() 시스템 콜을 통해 자식의 종료 정보를 받아야 하는데, 이 작업을 수행하지 않으면 좀비 상태로 남게 됩니다.

좀비는 실제로 메모리나 CPU를 점유하진 않지만, 프로세스 테이블의 항목을 계속 차지하기 때문에 누적되면 시스템 자원에 영향을 줄 수 있습니다.

 

✔️ Ubuntu 예시

ps -ef | grep defunct

위 명령어를 실행하면 <defunct> 상태로 표시되는 프로세스를 확인할 수 있습니다. <defunct>는 좀비 프로세스를 나타내며, 이는 주로 부모 프로세스가 자식의 종료를 제대로 처리하지 않을 때 발생합니다.

 

➤ 출력 예시

ubuntu    2351  1234  0 12:31 ?  00:00:00 [python3] <defunct>
ubuntu    2354  1234  0 12:31 ?  00:00:00 [script.sh] <defunct>

▸ PID 2351, 2354: 좀비 프로세스의 프로세스 ID입니다.
▸ PPID 1234: 이 프로세스들의 부모 프로세스입니다.
▸ <defunct>: 이 상태가 바로 좀비임을 나타냅니다.
▸ 실제로는 실행되지 않으며 CPU/메모리를 사용하지 않습니다.

 

➤ 좀비 프로세스를 직접 kill 할 수는 없습니다!

▸ 좀비 프로세스는 이미 종료된 상태입니다. 즉, kill 명령으로 직접 종료할 수 없습니다.
▸ 대신, 부모 프로세스(PPID)를 종료하거나 재시작해야 좀비가 사라집니다.(재시작: sudo reboot)

부모 프로세스를 종료하면 해당 프로세스가 수행 중이던 작업도 강제 종료됩니다. 서버나 중요한 작업 중인 경우엔 신중히 판단해야 합니다.

 

🔷 고아 프로세스(Orphan Process)

고아 프로세스는 반대로, 부모 프로세스가 먼저 종료된 상황에서 발생합니다. 부모가 사라졌기 때문에 더 이상 관리해 줄 주체가 없는 자식 프로세스가 된 것입니다.


Linux나 Ubuntu 환경에서는 이러한 고아 프로세스를 init(PID 1) 또는 systemd가 자동으로 인계받아 관리하게 됩니다. 운영체제가 안정적으로 동작하도록 보장하는 구조 덕분에 고아 프로세스는 시스템에 큰 문제를 일으키진 않습니다.

 

✔️ Ubuntu 예시

고아 프로세스는 일반적으로 PPID(부모 프로세스 ID)가 1로 표시됩니다. 아래 명령어로 시스템에서 PPID가 1인 프로세스를 조회할 수 있습니다.

ps -eo pid,ppid,user,cmd | awk '$2==1'

➤ 출력 예시

  PID  PPID USER     CMD
 2123     1 ubuntu   /usr/bin/python3 child_process.py
 2170     1 ubuntu   /usr/bin/bash background_task.sh

PPID가 1인 프로세스가 고아 프로세스입니다.
여기서는 부모가 먼저 종료되어 systemd(PID 1)에 귀속된 상태입니다.
이들은 여전히 CPU/메모리 자원을 사용할 수 있습니다.

 

➤ 고아 프로세스 종료(kill) 방법

고아 프로세스는 일반 프로세스처럼 kill 명령어로 종료할 수 있습니다.

sudo kill 2123

SIGKILL 시그널로 강제 종료합니다.

 

✔️ Windows 예시

Windows 환경에서도 유사한 현상이 나타납니다.

예를 들어, 특정 서비스 프로세스가 비정상적으로 종료되었는데, 해당 서비스가 생성했던 자식 프로세스(예: 로깅 또는 백업 관련 프로세스)는 계속 실행되는 경우가 있습니다.

이런 고아 프로세스는 작업 관리자에서 종료되지 않고 남아 CPU 자원을 과도하게 사용하는 원인이 되기도 합니다.


이 경우에는 작업 관리자(Task Manager) 또는 Process Explorer 같은 고급 도구를 활용해 고아 상태의 프로세스를 식별하고 수동으로 종료하는 것이 필요합니다.

 

✔ 마무리 - 프로세스를 이해해야 시스템을 통제할 수 있습니다.

운영체제의 핵심 개념인 프로세스(Process)는 단순한 실행 단위가 아닙니다.

이는 프로그램이 실제로 살아 움직이며, 시스템 자원을 할당받고, 상태를 변화시키며, 다른 프로세스와 협력하는 동적인 존재입니다.


실무 환경에서 이 지식은 다음과 같은 상황에 직접 연결됩니다
🔸 프로그램이 느려지는 원인 분석 시, CPU를 점유 중인 특정 프로세스 식별
🔸 좀비/고아 프로세스 문제 해결 시, 프로세스 종료 흐름 및 자식 프로세스 처리 이해
🔸 IPC 구조 설계 시, 어떤 통신 방식이 구조와 성능에 유리한지 선택 가능
🔸 서비스 장애 대응 시, 프로세스 상태(Waiting, Running, Blocked 등)를 기반으로 진단
🔸 운영 자동화 시, ps, top, kill, wait, exec 등 명령어를 활용한 프로세스 제어 스크립트 작성

 

실무에서 운영체제를 잘 다루는 개발자일수록, 프로세스가 어떻게 생성되고, 통신하며, 종료되는지에 대한 감각을 가지고 있습니다.

 

 

 

※ 게시된 글 및 이미지 중 일부는 AI 도구의 도움을 받아 생성되거나 다듬어졌습니다.

반응형

 

반응형