프로세스
개요
이 글에서는 운영체제에서 프로세스가 무엇인지 이해하기 위해 프로세스의 메모리 구조와 상태, 프로세스 제어 블록(PCB), 문맥에 대해 공부한다.
프로세스란?
프로세스는 실행 중인 프로그램을 의미한다. 더 자세히 설명하자면, 컴퓨터에서 실행파일(. exe)을 실행하면 메모리에 해당 실행파일(코드)의 데이터들이 올라가고 CPU가 그 데이터를 한 줄씩 실행한다. 이때 메모리에 올라가서 CPU에 의해 실행되는 데이터를 프로세스라고 하는 것이다.
프로세스는 각각이 독립적으로 실행된다. 따라서 원칙적으로는 프로세스 A의 실행이 프로세스 B에 아무런 영향을 미치지 못 한다. 하지만 프로세스 간 자원을 공유하고 데이터를 주고받는 프로세스 간 통신(IPC)도 존재한다. IPC는 다음에 다룰 예정이다!
프로세스의 메모리 구조
메모리에 올려 실행되는 데이터를 프로세스라고 했다. 각 프로세스는 자기만의 메모리 구조를 갖는다.
위의 그림처럼 프로세스의 메모리 공간은 4개의 영역으로 나뉜다. 정적 영역인 코드 영역(텍스트 영역), 데이터 영역과 동적 영역인 힙 영역, 스택 영역이다. 각각에 대해 알아보자.
1. Text 영역
- Code 영역이라고도 한다.
- 프로그램을 실행시키는 실행 파일 내의 명령어가 저장된다.
- 기계어로 이루어진 명령어가 저장된다.
- 읽기 전용 공간이다.
2. Data 영역
- 프로그램이 실행되는 동안 유지할 데이터가 저장된다. ( 예 - 전역 변수, 정적 변수, 상수 )
3. Heap 영역
- 동적 할당을 위한 메모리 영역
- 사용자가 직접 할당할 수 있는 동적인 크기의 저장 공간
4. Stack 영역
- 데이터를 일시적으로 저장하는 공간이다. ( 예 - 매개변수, 지역변수 등 )
- stack 구조를 사용한다.
- stack 포인터를 사용해 상태를 관리한다.
스택 영역과 힙 영역은 모두 동적 영역으로, 크기가 정해져있지 않기 때문에 두 개가 겹치지 않도록 해야 한다. 이를 위해 힙 영역은 메모리의 아래에서 위로, 스택 영역은 위에서 아래로 할당한다.
프로세스의 상태
프로세스에는 여러 상태가 있다.
- 생성 상태(new) : 이제 막 메모리에 적재되어 PCB를 할당받은 상태
- 준비 상태(Ready) : 당장이라도 실행 가능하지만, CPU를 기다리는 상태
- 실행 상태(Running) : CPU를 할당받아 실행 중인 상태
- 대기 상태(Blocked) : 프로세스 실행 도중 I/O 장치를 사용 중인 경우. I/O 장치가 입출력을 끝낼 때까지 기다리는 중
- 종료 상태(Terminated, exit) : 프로세스가 종료된 상태로, 운영체제가 PCB와 프로세스가 사용한 메모리를 정리한다.
프로세스 제어 블록(PCB)
CPU는 한 번에 하나의 프로세스를 실행할 수 있다. 따라서 어떤 프로세스에게 CPU를 포함한 자원들을 사용하게 해 줄지를 정하는 일이 매우 중요하다. 이런 역할을 운영체제가 하는 것이다. 그런데 어떤 프로세스가 언제 실행되어야 할지, 아니면 이 프로세스가 뭐 하는 프로세스인지, 어느 주소에 저장되어 있는지 같은 정보들은 어떻게 알아낼 수 있을까? 그걸 알아야 해당 프로세스에게 어떤 자원을 언제 얼마동안 배분해야 할지 알 수 있을 텐데 말이다. 고맙게도 프로세스들은 네임택처럼 저마다의 정보를 프로세스 제어 블록(PCB)에 담아두고 있다. 따라서 운영체제는 PCB를 보고 프로세스를 식별하고 어떻게 처리할지를 판단할 수 있다.
즉, PCB는 프로세스에 대한 메타데이터를 저장한 데이터다. 프로그램이 실행되면 프로세스가 생성되고, 프로세스 메모리가 할당된다. 그리고 이 프로세스의 메타데이터들이 PCB에 저장되고 관리된다.
PCB의 특징
- 커널 영역에 생성된다. 중요한 정보를 포함하기 때문에 일반 사용자가 접근할 수 없도록 하기 위함이다.
- 프로세스 생성 시에 만들어지고 실행이 끝나면 폐기된다.
PCB에 담기는 정보들
- 프로세스 ID(PID) : 특정 프로세스를 식별하기 위해 부여하는 고유 번호
- 레지스터 값 : 해당 프로세스를 실행하며 사용했던 프로그램 카운터를 비롯한 레지스터 값. 이 값들을 저장해둬야 실행 차례 이후에도 이전까지 진행했던 작업들을 그대로 이어 실행할 수 있다.
- 프로세스 상태 : 실행(Running), 준비(Ready), 대기(Waiting) 등의 상태 정보
- CPU 스케줄링 정보 : 프로세스가 언제, 어떤 순서로 CPU를 할당 받을지에 대한 정보
- 메모리 관리 정보 : 프로세스가 어느 주소에 저장되어 있는지, 페이지 테이블 정보
- 사용한 파일과 입출력 장치 목록
프로세스의 특정 시점 상태, 프로세스 문맥(Process Context)
프로세스의 특정 시점의 상태를 프로세스 문맥이라고 한다. 프로세스 문맥에는 프로그램 카운터를 포함한 레지스터 값, 메모리 정보, 실행을 위해 열었던 파일이나 사용한 입출력장치 등의 중간 정보가 포함된다. 즉, 프로세스 문맥은 곧 PCB의 정보다.
프로세스 문맥은 왜 필요한가? CPU가 프로세스 A에서 프로세스 B로 넘어갈 때를 생각해 보자. 프로세스 A는 CPU를 차지해서 뭔가를 열심히 했을 것이다. 뭔가 열심히 해놓고 아무 행동도 하지 않고 프로세스 B로 실행 순서를 넘겨준다는 것은 밤새 과제를 해놓고 그걸 저장하지 않은 상태로 노트북을 덮는 것과 똑같다. 당연하게도 기존에 사용하던 프로세스의 현재까지의 정보를 백업해두어야 한다. 이때 '현재까지의 정보'를 문맥이라고 하는 것이다. 또한 현재까지의 정보를 PCB에 백업하고, 다음 프로세스의 정보를 다음 프로세스의 PCB로부터 불러와 실행하는 것을 문맥 교환이라고 한다.
프로세스 A에서 프로세스 B로 CPU가 넘어갈 때, 문맥 교환의 과정을 간략히 정리한다면 다음과 같다.
- 프로세스 A의 현재 상태를 프로세스 A의 PCB에 저장한다.
- 프로세스 B의 PCB에서 프로세스 B의 문맥을 복구해온다.
- 프로세스 B를 실행한다.
이렇게 문맥 교환이 일어날 때 사용자의 입장에서는 동시에 여러 프로세스들이 실행되는 것처럼 보인다. 실제로는 CPU 하나가 한 프로세스만을 실행할 수 있는데 문맥 교환으로 인해 사용자의 눈에는 동시에 여러 프로세스가 실행되는 것처럼 보인다고 해서 동시성(Concurrency)이라고 한다.
문맥 교환은 오버헤드가 발생하는 작업이기 때문에 너무 자주 일어나면 성능을 저하시키는 원인이 된다. 따라서 운영체제는 프로세스를 적절히 스케줄링해야 하는 중대한 역할을 갖고 있다.