기록공간

2장. 가상화 본문

OS

2장. 가상화

입코딩 2020. 2. 7. 18:34
반응형

CPU 가상화

앞서 우리는 CPU의 가상화에 대해서 살펴보았다. 운영체제는 여러 개의 CPU가 존재한다는 환상을 제공하고 이는 프로세스 하나를 실행하고, 멈추고, 다른 프로세스를 실행하는 반복 과정인 시분할(Time Sharing)을 통해 이루어진다. 하지만 프로세스가 많아지면 CPU를 공유해야 할 대상도 많아지기 때문에 속도가 느려진다.

 

프로세스

앞에서 계속해서 프로세스라는 단어가 나왔는데, 도대체 무슨 뜻일까? 프로세스(Process)는 운영체제가 제공하는 핵심 개념 중 하나로 실행 중인 프로그램이다. 프로그램 자체는 생명이 없는 존재와 같다. 프로그램은 디스크 상에 존재하며 실행을 위한 명령어와 정적 데이터의 묶음일 뿐이다. 이것들을 읽고 실행하여 프로그램에 생명을 불어넣는 것이 운영체제이다.

 

프로세스의 구성 요소를 이해하기 위해서 하드웨어 상태(Machine state)를 이해해야 한다. 프로그램이 실행되는 동안 하드웨어 상태를 읽거나 갱신할 수 있다. 이때 가장 중요한 구성 요소는 무엇일까?

 

프로세스의 하드웨어 상태 중 가장 중요한 구성 요소는 메모리(Memory)이다. 명령어는 메모리에 저장된다. 읽고 쓰는 데이터 역시 메모리에 저장된다. 프로세스가 접근할 수 있는 메모리(주소 공간)는 프로세스를 구성하는 요소이다.

 

레지스터도 프로세스의 하드웨어 상태를 구성하는 요소 중 하나이다. 많은 명령어들이 레지스터를 직접 읽거나 갱신한다. 프로세스를 실행하는 데 레지스터도 빠질 수 없다. 프로세스의 하드웨어 상태를 구성하는 레지스터 중에 특별한 레지스터들이 존재한다. 

 

프로그램 카운터(Program counter, PC)는 프로그램의 어느 명령어가 실행 중인지를 알려준다. 프로그램 카운터는 명령어 포인터(Instruction pointer, IP)라고도 불린다.  

 

스택 포인터(Stack pointer)프레임 포인터(Frame pointer)는 함수의 변수와 리턴 주소를 저장하는 스택을 관리할 때 사용하는 레지스터이다.

 

프로세스 API

운영체제가 반드시 API로 제공해야 하는 몇몇 기본 기능에 대해 간단하게 살펴보도록 하겠다. 이 API들은 형태는 다르지만 모든 현대 운영체제에서 제공한다.

 

  • 생성(Create) : 운영체제는 새로운 프로세스를 생성할 수 있는 방법을 제공한다. 쉘에 명령어를 입력하거나, 응용 프로그램의 아이콘을 더블-클릭하여 프로그램을 실행시키면, 운영체제는 새로운 프로세스를 생성한다.

  • 제거(Destroy) : 운영체제는 프로세스를 강제로 제거할 수 있는 인터페이스를 제공해야 한다. 물론, 많은 프로세스는 실행되고 할 일을 마치면 프로세스를 종료한다. 그러나 프로세스가 스스로 종료하지 않으면 사용자는 그 프로세스를 제거하길 원할 것이고, 필요 없는 프로세스를 중단시키는 API는 매우 유용하다.

  • 대기(Wait) : 때론 어떤 프로세스의 실행 중지를 기다릴 필요가 있기 때문에 여러 종류의 대기 인터페이스가 제공된다.

  • 각종 제어(Miscellaneous Control) : 프로세스의 제거, 대기 이외에, 여러 가지 제어 기능들이 제공된다. 예를 들어, 대부분의 운영체제는 프로세스를 일시 정지하거나 재개하는 기능을 제공한다.

  • 상태(Status) : 프로세스 상태 정보를 얻어내는 인터페이스도 제공된다. 상태 정보에는 얼마 동안 실행되었는지 또는 프로세스가 어떤 상태에 있는지 등이 포함된다.

 

프로세스 생성

운영체제는 어떻게 프로그램을 준비하고 실행시킬까?이것에 관해서 자세하게 알아보자. 

 

프로세스 생성과정을 그림으로 표현한것

우선 처음으로 운영체제가 하는 작업은 프로그램 코드와 정적 데이터(예를 들면, 전역 변수)를 메모리, 프로세스의 주소 공간에 탑재(Load)하는 것이다. 코드와 정적 데이터를 메모리에 탑재하기 위해서 운영제체는 디스크의 해당 바이트를 읽어서 메모리의 어딘가에 저장해야 한다. 보통 프로그램 파일 자체가 실행 가능한 포맷으로 작성되어 있다. 그래서 실행을 하면 운영체제가 자동으로 탑재 작업을 한다. 

 

초기 운영체제들은 프로그램 실행 전에 코드와 데이터를 모두 메모리에 탑재하였다. 현대의 운영체제들은 이 작업을 늦추었다. 즉, 프로그램을 실행하면서 코드나 데이터가 필요할 때 필요한 부분만 메모리에 탑재한다. 이것을 게으른(Lazy) 적재라고 부른다.

 

코드와 정적 데이터가 메모리로 탑재된 후, 프로세스를 실행시키기 전에 운영체제가 해야 할 몇 가지가 있다. 일정량의 메모리가 프로그램의 실행시간 스택(Run-time stack)으로 할당되어야 한다. C 프로그램은 지역 변수, 함수 인자, 리턴 주소 등을 저장하기 위해 스택을 사용한다. 운영체제는 스택을 주어진 인자로 초기화한다. main()의 argc와 argv벡터를 이용하여 스택을 초기화 한다.

 

운영체제는 프로그램의 힙(Heap)을 위한 메모리 영역을 할당한다. C 프로그램에서 동적으로 할당된 데이터를 저장하기 위해 사용한다. 프로그램은 malloc()이나 new를 호출하여 필요한 공간을 운영체제에게 요청하고 free()나 delete를 호출하여 사용했던 공간을 반환하여 다른 프로그램이 사용할 수 있도록 운영체제에게 요청할 수 있다. 힙은 연결 리스트, 해시 테이블, 트리 등 크기가 가변적인 자료 구조를 위해 사용된다. 

 

운영체제는 또 입출력과 관계된 초기화 작업을 수행한다. 예를 들어, Input / Output 초기화가 있다. 이는 기본적으로 각 프로세스별로 표준 입력(STDIN), 표준 출력(STDOUT), 표준 에러(STDERR) 파일 디스크립터(File descriptor)를 갖는다. 이 작업은 입출력 작업을 쉽게 해 준다.

 

위 과정을 모두 거치면 운영체제는 프로그램을 실행할 준비를 마치게 된다. 이제 프로그램의 시작 지점인 main()에서부터 프로그램 실행을 시작하는 작업을 진행한다. main() 루틴으로 분기함으로써, 운영체제는 CPU를 새로 생성된 프로세스에게 넘기게 되고 프로그램 실행이 시작된다.

 

프로세스 상태

프로세스가 무엇이고, 어떻게 생성되는지 살펴봤으니, 이제 프로세스의 상태에 대해 논의해보자. 프로세스 상태를 단순화하면 다음 세 상태 중 하나에 존재할 수 있다.

 

  • 실행(Running) : 실행 상태에서 프로세스는 프로세서에서 실행 중이다. 즉, 프로세스는 명령어를 실행하고 있다.

  • 준비(Ready) : 준비 상태에서 프로세스는 실행할 준비가 되어 있지만 운영체제가 다른 프로세스를 실행하고 있는 등의 이유로 대기 중이다.

  • 대기(Blocked) : 프로세스가 다른 이벤트를 기다리는 동안 프로세스의 수행을 중단시키는 연산이다. 예를 들어 프로세스가 디스크에 대한 입출력 요청을 하였을 때 프로세스는 입출력이 완료될 때까지 대기 상태가 되고, 다른 프로세스가 실행 상태로 될 수 있다.

상태 전이

프로세스는 준비 상태와 실행 상태를 운영체제의 정책에 따라 이동한다. 프로세스는 운영체제의 스케줄링 정책에 따라 스케줄이 되면 준비 상태에서 실행 상태로 전이한다. 

 

실행 상태에서 준비 상태로의 전이는 프로세스가 나중에 다시 스케줄 될 수 있는 상태가 되었다는 것을 의미한다. 프로세스가 입출력 요청 등의 이유로 대기 상태가 되면 요청 완료 등의 이벤트가 발생할 때까지 대기 상태로 유지된다. 이벤트가 발생하면 프로세스는 다시 준비 상태로 전이되고 운영체제의 결정에 따라 바로 다시 실행될 수도 있다.

 

CPU가 한 개이고 입출력 작업을 할때 상태 변환

위 그림을 보면 첫 번째 프로세스가 어느 정도 실행한 후에 입출력을 요청한다. 그 순간 프로세스는 대기 상태가 되고 다른 프로세스에게 실행 기회를 준다.

 

자료 구조

운영체제도 일종의 프로그램이다. 다른 프로그램들처럼 다양한 정보를 유지하기 위한 자료 구조를 가지고 있다. 예를 들면, 프로세스 상태를 파악하기 위해 준비 상태의 프로세스들을 위한 프로세스 리스트(Process list)와 같은 자료 구조를 유지한다. 또한 어느 프로세스가 실행 중인지 파악하기 위한 부가적인 자료 구조도 유지한다. 운영체제는 또 대기 상태인 프로세스도 파악해야 한다. 입출력 요청이 완료되면 운영체제는 적절한 프로세스를 깨워 준비 상태로 다시 전이시킬 수 있어야 한다.

 

운영체제가 관리하는 핵심자료들
레지스터 문맥 자료구조 : 프로세스의 정보를 어떻게 관리하는지 대략적으로 보여주고 있다.

이러한 자료구조를 PCB(Process Control Block)이라고도 부른다.

반응형
Comments