Back

프로세스 (1)

CPU 가상화, 정의, 상태변화

Virtualization (가상화)

가상화는 실제 대상을 가상의 대상으로 바꾸는 것을 의미한다.

복숭아를 가상화해보자
복숭아를 가상화해보자

실제로 존재하는 복숭아(Physical peach)는 하나이다. 그런데 여러 사용자가 이를 원하는 경우, 복숭아를 가상화하여 가상의 복숭아(Virtual peach)를 여러 개 만들 수 있다. 그리고 이것들을 복숭아를 원하는 사람들에게 나눠준다.

가상의 복숭아를 갖고 있는 사람들은 자기만 전용으로 사용하는 복숭아를 갖고 있다는 착각에 빠지는데, 그 이유는 다음과 같다.

  • 자기가 가지고 있는 가상의 복숭아만 알 수 있다.
  • 다른 사람들이 존재한다는 사실도 모른다.
  • 따라서 다른 사람들의 가상의 복숭아를 알 수 없다.
  • 심지어, 자신의 복숭아가 가상화되어 있다는 사실도 모른다.

이것이 운영체제가 수행하는 가상화의 기본 아이디어이다.

그런데 실제 복숭아는 하나밖에 없는데, 어떻게 전용의 복숭아를 가지고 있다는 환상이 유지될까? 다른 사람이 쓰면 다른 누군가는 쓰지 못하지 않을까?

결론부터 말하자면, “가상의 복숭아"라는 환상은 각 사람이 항상 복숭아를 사용하지 않기 때문에 유지될 수 있다.

각 사람은 자신이 가지고 있는 가상의 복숭아를 잠깐 사용하지만, 나머지 대부분의 시간은 낮잠을 자기도 하고, 다른 일을 하기도 한다.

운영체제는 중간에서 A라는 사람이 짧은 시간 동안 복숭아를 사용하고 나면 B에게 주고, B가 또 짧은 시간 동안 복숭아를 사용한 후에 C에게 복숭아를 주는 작업을 중간에서 수행한다.

즉, 각 사람이 복숭아를 사용하지 않을 때는 다른 사람이 사용할 수 있도록 이리저리 옮겨 준다.

물론 한 사람이 항상 복숭아를 사용하고 있다면 가상의 복숭아라는 환상이 깨지게 되겠지만, 실제로 각 사람이 복숭아를 필요로 하는 시간은 매우 짧기 때문에, 각 사람이 전용의 복숭아를 가지고 있다는 같은 환상을 잘 유지할 수 있다.

이로부터 알 수 있는 가상화의 특징을 정리해보면 다음과 같다.

  • 각 사람에게 가상의 복숭아를 나눠 준다.
  • 각 사람은 매우 짧은 시간동안 복숭아를 사용하므로, 자신만의 전용 복숭아를 가지고 있다는 착각에 빠진다.

당연하겠지만 실제로는 복숭아 대신 CPU, Memory 등을 가상화해서 제공한다.

먼저 CPU 가상화를 살펴볼텐데, CPU 가상화를 공부하려면 프로세스에 대해 알아야 한다.

Process (프로세스)

프로세스는 프로그램이 실행 중인 상태를 의미한다.

운영체제와 외부 구조
운영체제와 외부 구조

운영체제(Operating System)은 하드웨어 자원들을 관리하고, 프로세스들이 **시스템 콜(System call)**을 통해 하드웨어 자원을 요청하면 해당 자원을 가상화하여 프로세스에게 제공해 준다.

프로세스 작동 과정(Running a Process)

프로세스는 다음 과정을 반복해서 수행한다.

Fetch Decode Execute Update
인스트럭션 가져오기 가져온 인스트럭션 해석 해석한 결과를 실행 새로운 인스트럭션 업데이트

여러 개의 프로세스를 작동시키고 싶으면 가장 간단하게 사용 가능한 방법은 프로세스마다 CPU를 할당하는 것이다.

그러나 실행 가능한 프로세스의 수는 수백 가지인데, CPU의 갯수는 멀티코어 환경이라고 하더라도 2자릿수를 넘기기가 힘들다.

따라서 그 다음으로 생각할 수 있는 방식은 프로세스 간의 **인터리빙(Interleaving, 교차)**이다.

즉, 프로세스 A의 코드를 실행하다가 일정 시간이 지나면 잠시 멈춘 후 프로세스 B의 코드를 실행하고, 마찬가지로 일정 시간이 지나면 프로세스 C의 코드를 실행하는 것이다.

인터리빙 방식의 문제는 프로세스 A의 코드에서 프로세스 B의 코드로 직접 이동해야 한다는 점이다. 즉, 전용의 CPU를 사용한다는 환상이 깨진다. 다른 프로세스에게 CPU를 직접 양보해야 하기 때문이다.

운영체제도 일종의 프로그램이므로, 자신의 코드를 가지고 있다. 따라서 위와 같은 인터리빙 방식에서 운영체제를 거치도록 하여 인터리빙을 수행하면 가상화의 환상을 깨뜨리지 않고도 각 프로세스의 코드를 실행할 수 있다.

왼쪽 : 직접 인터리빙 / 오른쪽 : OS 인터리빙
왼쪽 : 직접 인터리빙 / 오른쪽 : OS 인터리빙

왼쪽 방식에서는 프로세스 A가 프로세스 B에게 CPU를 직접 양보했다면, 오른쪽 방식에서는 실행 중인 프로세스 A로부터 CPU를 운영체제가 받아서 프로세스 B에게 전달함으로써 가상화를 유지할 수 있다.

이렇게 CPU의 시간을 잘게 나누어서 각 프로세스에게 나눠 주는 방식을 Time Sharing이라고 하며, 현대 대부분의 운영체제들이 채택하고 있는 방식이다.

프로세스란?

앞서 이야기했듯 프로세스는 실행 중인 프로그램을 의미한다.

객체지향과 비교해서 생각하면 다음과 같은 비유가 가능하다.

Static Dynamic
클래스(Class) 인스턴스(Instance)
프로그램 프로세스

프로세스의 특징은 다음과 같다.

  • Protection의 기본적인 단위이다. 프로세스 단위로 자원을 할당하고, 해당 자원에는 다른 프로세스가 간섭할 수 없다.
  • PID(Process ID)를 통해 식별할 수 있다.
  • 프로세스의 동적인 상태를 정의하는, 다음과 같은 정보들을 포함한다.
    • CPU context (Program counter, Stack pointer)
    • OS resources (address space, open files, etc.)
    • Other information (PID, state, owner, etc.)

프로세스의 실행 과정 (Process Creation)

  1. 프로그램 코드를 메모리에 로드한다.
    • 메모리 내 프로세스별로 할당된 주소 공간에 로드한다.
    • 메모리에 로드 시, 프로그램의 코드를 한번에 전부 로드하는 것이 아닌 필요한 부분만 그때그때 로드한다(Lazily Load) : 메모리 가상화의 Demand Paging 기법
  2. 프로그램을 실행하기 위한 런타임 스택을 할당한다.
    • 스택에는 지역 변수, 함수의 매개변수, 반환 주소 등이 저장된다.
  3. 동적 할당을 위한 Heap 공간을 할당한다.
    • 프로세스별로 동적인 공간 할당 요청이 있을 경우 Heap 공간에서 메모리를 할당한다.
    • C에서는 malloc()을 사용해 메모리를 할당받고 free()를 사용해 할당을 해제한다.
  4. OS에 의해 초기화 작업이 수행된다.
    • 모든 프로그램은 기본적으로 3개의 오픈 파일 디스크립터를 만들어 준다.
      • 표준 입력, 표준 출력, 표준 에러
  5. CPU의 제어권이 OS로부터 새로 생성된 프로세스에게 넘어간다.

프로세스의 상태 (Process States)

프로세스는 다음 3가지 중 하나의 상태를 갖는다.

  • 실행 중 (Running) : CPU를 할당받아 실행 중인 상태

  • 대기 중 (Ready) : 실행될 준비는 끝냈지만 CPU를 할당받지 못한 상태

  • 정지 (Blocked) : 모종의 이유로 실행이 잠시 중단된 상태

    • 입출력과 같은 오래 걸리는 작업을 수행하는 경우
    • 사용자 입력과 같은 이벤트를 기다리고 있는 경우

    프로세스 간 상태 전이 관계도
    프로세스 간 상태 전이 관계도

  • 프로세스는 기본적으로 Ready 상태와 Running 상태를 계속 오가며 실행된다.

    • 프로세스가 처음 생성되면 Ready 상태가 된다.
    • CPU를 할당받아 Running 상태가 된다.
    • 정해진 할당 시간(Time slice)을 모두 사용하면 Ready 상태가 된다.
  • Running 상태에서 입출력(I/O) 혹은 사용자 Event를 기다려야 하는 경우 Blocked 상태가 된다.

  • Blocked 상태에서 필요한 작업을 다 처리하면 Ready 상태가 된다.

    • 다시 Ready와 Running 두 상태의 전이를 반복한다.

Linux에서의 프로세스

리눅스 Shell에서 ps ax명령어를 입력하면 현재 실행 중인 프로세스 목록을 확인할 수 있다.

PID, 프로세스의 현재 상태 등을 확인할 수 있다. 프로세스의 상태를 나타내는 기호에는 다음과 같은 것들이 있다.

기호 의미 상세
R Running or Runnable Running or Ready
S Sleeping
T Traced or Stopped Blocked
D Uninterruptible Sleep (주로) I/O
Z Zombie *중요

Zombie 상태는, 프로세스 자체는 종료되었지만 관련 데이터가 아직 삭제되지 않은 상태를 말한다.

그밖에 위 기호와 함께 표기해 추가적인 정보를 나타내 주는 기호들도 있다.

기호 의미 상세
< High-priority task 높은 우선순위
N Low-priority task 낮은 우선순위
s Session leader Shell Program
+ Foreground Process Group 포그라운드 프로세스
l Multi-threaded 멀티스레드 프로세스

프로세스 종료

프로세스는 다음과 같은 경우 종료된다.

  • 자발적(Voluntary) 종료 : 의도된 종료
    • Normal exit : 프로그램이 끝까지 모두 실행된 상태
    • Error exit : 에러가 발생한 경우 코드 중간에 exit()를 사용해 종료
  • 비자발적(Involuntary) 종료 : 의도되지 않은, 시스템에 의한 종료
    • Segmentation fault : 잘못된 메모리에 접근한 경우
    • Protection fault : 접근해서는 안 되는 자원에 접근한 경우
    • Exceed allocated resource : 할당된 자원을 초과해서 사용한 경우
    • Killed by another process : 커널에서 프로그램 실행 도중 ^C (Ctrl + C)를 입력하는 경우 등

또한 위에서도 언급했지만, 좀비 프로세스는 종료되고 난 후에도 관련 데이터가 삭제되지 않은 프로세스를 말한다.

다음 글에서는 프로세스 관련 정보에 대해 알아본다.

comments powered by Disqus