프로세스
프로세스 개념
운영 체제에 대해 이야기 할 때 제기되는 질문중 하나는 CPU가 수행하는 모든 활동을 무엇이라고 부를 것인가이다. 초기 컴퓨터는 job을 실행하는 일괄 처리(batch) 시스템이었지만, 이후 user program, 또는 task를 실행하는 시분할 시스템이 등장했다. 오늘날 단일 사용자 시스템에서도 사용자는 워드 프로세서, 웹 브라우저, 이메일 패키지 등 여러 프로그램을 동시에 실행할 수 있다. 멀티태스킹을 지원하지 않는 임베디드 장치처럼 컴퓨터가 한 번에 하나의 프로그램만 실행할 수 있더라도, 운영 체제는 메모리 관리와 같은 자체적인 내부 프로그래밍 활동을 지원해야 할 수 있다. 많은 측면에서 이러한 모든 활동은 유사하므로, 이 모든 활동을 프로세스(process)라고 부른다.
조금 더 현대적인 용어는 프로세스이지만, job(작업) 이라는 용어는 역사적인 의미를 지닌다. 운영 체제의 주요 작업이 job processing이였던 시기에 운영 체제 이론과 용어의 상당 부분이 형성되었기 때문이다.
따라서 적절한 맥락에서는 운영 체제의 역할을 설명할 때 job(작업)을 사용한다. 예를 들어, '프로세스'가 'job'을 대체한 용어라고 해서 작업 스케줄링(job scehduling)처럼 널리 통용되는 용어까지 배제하려 한다면, 오히려 혼란을 초래할 수 있다.
프로세스
앞서 언급했듯이 비공식적으로 프로세스는 실행 중인 프로그램이다. 프로세스의 현재 활동 상태는 프로그램 카운터(program counter)의 값과 프로세서 레지스터의 내용으로 표현된다. 프로세스의 메모리 레이아웃은 일반적으로 여러 섹션으로 나뉘며, 다음 그림에 제시된다:
위 메모리 레이아웃의 섹션은 다음과 같은 역할을 한다:
- Text 영역: 실행 가능한 코드
- Data 영역: 전역 변수
- Heap 영역: 프로그램 실행 시간 동안 동적으로 할당되는 메모리
- Stack 영역: 함수를 호출할 때 임시 데이터 저장 (함수 매개변수, 반환 주소, 로컬 변수 등)
Text와 Data 영역의 크기는 프로그램 실행 중에 도중에 변경되지 않는다. 그러나 스택과 힙 영역은 프로그램 실행 중에 동적으로 축소되거나 확장될 수 있다. 함수가 호출될 때 마다 함수 매개변수, 지역 변수 그리고 반환 주소가 포함된 활성화 레코드(activation record)가 스택에 push 된다. 함수에서 제어권(control)이 반환되면 활성화 레코드는 스택에서 pop된다. 이와 유사하게 힙은 메모리가 동적으로 할당됨에 따라 커지고 메모리가 시스템에 반환되면 줄어든다. 스택 힙 영역은 서로를 향해 커지며, 운영 체제는 서로 겹치지 않도록 관리해야 한다.
우선 프로그램은 프로세스가 아니라는 점을 분명히 해야한다. 프로그램은 디스크에 저장된 명령어들의 집합, 즉 실행 가능한 코드가 담긴 정적인 파일(실행 파일, executable file)이다. 반면에 프로세스는 프로그램을 기반으로 실행되며, 다음에 수행할 명령어를 가리키는 프로그램 카운터와 각종 실행 리소스를 포함하는 능동적인 개체이다.
실행 파일이 메모리에 로드되면 프로그램은 프로세스가 되며 이러한 실행은 다음 두 가지 방식으로 이루어진다.
- 실행 파일 아이콘을 더블 클릭
- 커맨드 라인에서 실행 파일 이름을 직접 입력 (`prog.exe`, `a.out`)
서로 다른 두 프로세스가 동일한 프로그램을 기반으로 생성될 수 있지만, 이들은 별개의 실행 흐름으로 간주 된다. 예를 들어 여러 사용자가 각각 메일 프로그램을 실행하거나, 한 사용자가 웹 브라우저를 여러 창으로 실행하는 경우가 그렇다. 이와 같은 각 프로세스는 동일한 텍스트 영역(코드)는 동일하지만, 힙, 스택 영역은 모두 독립적으로 유지된다. 또한 한 프로세스가 실행되면서 여러 프로세스를 생성하는 경우도 흔하다.
또한 프로세스가 다른 코드의 실행 환경이 될 수 있다는 점도 중요하다. 대표적인 예로 Java 프로그래밍 환경을 들 수 있다. 대부분의 경우, Java로 작성된 실행 파일은 직접 실행되지 않고 Java 가상 머신(JVM) 내에서 실행된다. JVM은 Java 코드를 로드하여 해석하고, 그 결과를 네이티브 명령어로 실행하는 하나의 프로세스로 동작한다. 예를들어, 컴파일된 Java 클래스 파일 Program.class를 실행할 때는 다음과 같이 입력한다:
java program
여기서 `java` 명령어는 JVM을 일반 프로세스로 실행하며, JVM은 그 안에서 Program을 실행한다. 이 구조는 일종의 시뮬레이션과 유사하지만, 실행되는 코드는 다른 명령어 집합을 흉내 내는 것이 아니라 Java 언어로 작성된 점에서 차이가 있다.
C 프로그램의 메모리 레이아웃
아래 그림은 메모리에 있는 C 프로그램의 레이아웃이다. 프로세스가 실제 C 프로그램과 어떻게 연관되는지를 확인할 수 있다. 이 그림은 메모리에 있는 프로세스의 일반적인 개념과 유사하지만 몇 가지 차이점이 존재한다:
- 전역 데이터 영역은 (a)초기화된 데이터와 (b)초기화되지 않은 데이터 영역으로 분리된다.
- main() 함수에 전달되는 argc와 argv 매개변수에 대한 별도의 영약이 제공된다
GNU의 Size 명령어는 일부 영역들의 크기(byte)를 확인할 수 있다. 위 C 프로그램의 실행 파일 이름이 "memory"라고 가정을 하고size 명령어를 입력하면 다음과 같은 출력이 생성된다:
데이터 필드는 초기화되지 않은 데이터를 나타내고, bss는 초기화된 데이터를 나타낸다. (bss는 block started by symbol이라는 용어와 연관이 되어있다.) dec와 hex의 값은 10진수와 16진수로 표현된 세 영역의 합계이다. Stack과 Heap은 별도의 방법으로 확인을 해야할 수 있겠다는 생각이 든다.
참고 자료
- Abraham-Silberschatz-Operating-System-Concepts-10th-2018 *(3.1 Process Concept)
'Computer Science > OS' 카테고리의 다른 글
[운영체제] CPU 스케줄링 (0) | 2021.08.06 |
---|---|
[운영체제] - Blocking vs Non-Blocking / Sync vs Async (0) | 2021.06.28 |
[운영체제] 스케줄러에 대하여 (0) | 2021.06.24 |