사전 가상 머신
개념

가상 머신

gabury1

소프트웨어로 만들어 낸 기계 한 벌입니다. 위에 얹힌 쪽은 이것을 진짜 기계로 알고 명령을 냅니다. 아래쪽이 그 명령을 진짜 하드웨어에 넘기거나 대신 흉내 내 줍니다.

상세

어린이 요리 교실에는 아이들이 쓸 부엌이 한 벌 꾸며져 있습니다. 아이들은 그 부엌을 진짜 부엌으로 알고 제 손으로 씻고 썰고 섞습니다. 불을 켜려는 순간만은 선생님이 가로채 대신 해 줍니다.

"진짜 기계로 안다"는 것은 대개 그렇다는 말이지 조건은 아닙니다. 명령 집합만 내주는 갈래도 조건 밖입니다. 얹힌 쪽이 쓰는 것은 진짜 프로세서의 명령이 아니라 그 기계만의 이진 형식입니다.

기계 노릇을 하려면 두 가지가 있어야 합니다. 명령 집합, 그리고 그 명령이 값을 놓고 꺼내는 메모리 영역입니다. 이 둘을 갖추면 위에 얹힌 쪽은 명령을 하나씩 꺼내 실행하는 일을 계속할 수 있습니다. 진짜 프로세서가 하는 일이 바로 그것이기 때문입니다.

flowchart TD
    G["얹힌 쪽 · 운영체제나 프로그램"] -->|명령| V["가상 머신"]
    V -->|그대로 넘김| H["진짜 기계"]
    V -->|가로채서 대신 처리| E["흉내 내 주는 쪽"]
    E --> H

흉내 내는 범위는 하나로 정해져 있지 않습니다. 하드웨어 한 벌을 통째로 흉내 내 그 위에 운영체제를 얹기도 하고, 프로그램 하나에 명령 집합만 내주기도 합니다. 그 갈림이 이 표제어의 본체입니다.

배경

기계 한 대에는 운영체제 한 벌이 올라갑니다. 그 한 벌은 메모리도 프로세서도 장치도 전부 자기 것으로 알고 씁니다. 그래서 성격이 다른 작업 두 벌을 나란히 두려면 기계를 한 대 더 놓는 수밖에 없었습니다. 한 대를 놀리고 다른 한 대는 모자라는 일이 생겨도 옮겨 담을 방법이 없었습니다.

프로그램 쪽에도 같은 종류의 불편이 있었습니다. 컴파일한 결과는 그 기계의 명령 집합에 묶입니다. 기계가 바뀌면 같은 소스를 다시 컴파일해야 합니다.

두 불편의 답이 같았습니다. 진짜 기계를 내주는 대신, 진짜 기계처럼 보이는 것을 소프트웨어로 한 벌 만들어 내주는 것입니다. 그렇게 만들어 낸 기계를 가상 머신이라고 부릅니다. 공짜는 아닙니다 — 얹힌 쪽이 특권이 필요한 명령을 내면 그대로 돌게 둘 수 없어서, 가로채 아래쪽이 대신 처리해 줘야 합니다.

갈래

갈리는 축은 하나입니다. 무엇을 흉내 내는가.

시스템 가상 머신

하드웨어 한 벌을 통째로 흉내 냅니다. 그래서 위에 운영체제가 통째로 올라갑니다. 리눅스 커널이 내주는 KVM(Kernel-based Virtual Machine, 커널 기반 가상 머신)이 이 갈래입니다. KVM 공식 문서는 이 API(Application Programming Interface, 응용 프로그램 인터페이스)가 여러 종류의 파일 디스크립터와 그 디스크립터에 거는 ioctl(input/output control, 입출력 제어) 호출을 중심으로 짜여 있다고 적습니다. 문서의 표현으로는 "가상 머신의 여러 측면을 조종하기 위해 서로 다른 종류의 파일 디스크립터에 거는 ioctl 의 모음"입니다. 기계 한 벌이 이 호출들로 조립됩니다.

프로세스 가상 머신

프로그램 하나에 추상 명령 집합만 내줍니다. 하드웨어를 통째로 흉내 내지 않습니다. JVM(Java Virtual Machine, 자바 가상 머신) 명세는 자신을 추상 계산 기계라고 적습니다. 진짜 계산 기계처럼 명령 집합을 갖고 실행 중에 여러 메모리 영역을 다룬다고 합니다. 명세는 또 이 기계가 자바 프로그래밍 언어를 전혀 모른다고 못 박습니다. 아는 것은 클래스 파일이라는 이진 형식 하나뿐이고, 그 안에 가상 머신 명령과 심볼 테이블이 들어 있습니다. 명세는 언어를 가상 머신으로 구현하는 것이 꽤 흔한 일이라고 적습니다. 그리고 가장 잘 알려진 가상 머신은 UCSD(University of California, San Diego, 샌디에이고 캘리포니아 대학교) 파스칼의 P-code 기계일 것이라고 덧붙입니다.

웹 쪽에도 같은 갈래가 있습니다. WebAssembly 코어 명세는 자신의 계산 모델이 스택 머신에 기반한다고 적습니다. 코드는 순서대로 실행되는 명령의 나열이고, 명령은 겉으로 드러나지 않는 피연산자 스택 위의 값을 다룹니다. 단순 명령은 스택에서 인자를 꺼내 계산하고 결과를 다시 올려놓고, 제어 명령은 실행 흐름을 바꿉니다.

예시

KVM

리눅스 커널이 내주는 시스템 가상 머신입니다. /dev/kvm 을 열어 얻은 손잡이에서 시작해, 기계 한 벌이 호출 세 번으로 조립되고 돌기 시작합니다.

KVM_CREATE_VM 은 시스템 ioctl 입니다. 인자는 머신 타입 식별자(KVM_VM_*)이고, 새 가상 머신을 조종할 수 있는 VM 파일 디스크립터를 돌려줍니다. 문서는 이 시점의 가상 머신에 가상 프로세서도 메모리도 없다고 적습니다. 머신 타입으로는 아마도 0 을 쓰면 될 것이라고 안내합니다.

KVM_CREATE_VCPU 는 VM ioctl 입니다. 인자는 vcpu id 이고, x86 에서는 apic(Advanced Programmable Interrupt Controller, 고급 프로그래밍 가능 인터럽트 컨트롤러) id 입니다. 성공하면 vcpu 파일 디스크립터를, 실패하면 -1 을 돌려줍니다. 가상 프로세서를 가상 머신에 하나 붙이는 호출입니다. max_vcpus 보다 많이 붙일 수 없고, vcpu id 는 [0, max_vcpu_id) 범위의 정수입니다.

KVM_RUN 은 vcpu ioctl 입니다. 인자가 없고, 성공하면 0 을, 실패하면 -1 을 돌려줍니다. 게스트 가상 프로세서를 돌리는 호출입니다. 명시적 인자가 없는 대신 암묵적 인자 블록이 있습니다. vcpu 파일 디스크립터를 오프셋 0 에서 mmap 해 얻고, 크기는 KVM_GET_VCPU_MMAP_SIZE 가 알려줍니다. 그 블록은 struct kvm_run 모양으로 짜여 있습니다.

sequenceDiagram
    participant 앱
    participant 커널
    앱->>커널: /dev/kvm 열기
    커널-->>앱: kvm 손잡이
    앱->>커널: KVM_CREATE_VM
    커널-->>앱: VM 파일 디스크립터
    앱->>커널: KVM_CREATE_VCPU
    커널-->>앱: vcpu 파일 디스크립터
    앱->>커널: KVM_RUN
    커널-->>앱: 0 또는 -1

Java 가상 머신

JVM 명세 2장은 런타임 데이터 영역을 정의합니다. 일부는 가상 머신이 시작할 때 만들어져 가상 머신이 끝날 때만 사라집니다. 나머지는 스레드마다 따로 생기고, 스레드가 만들어질 때 생겨 스레드가 끝날 때 사라집니다. 그중 하나가 pc(program counter, 프로그램 카운터) 레지스터입니다. JVM 은 여러 실행 스레드를 한꺼번에 지원할 수 있고, 스레드마다 자기 pc 레지스터를 갖습니다.

명령 하나는 한 바이트짜리 opcode 로 시작합니다. 그 뒤에 인자나 데이터를 넘기는 피연산자가 0 개 이상 붙습니다. 피연산자 없이 opcode 하나로 끝나는 명령도 많습니다. 명세는 예외를 무시하면 인터프리터의 안쪽 루프가 사실상 이렇다고 적습니다.

do {
    atomically calculate pc and fetch opcode at pc;
    if (operands) fetch operands;
    execute the action for the opcode;
} while (there is more to do);

앞의 KVM 이 파일 디스크립터에 호출을 걸어 기계를 조립했다면, 이쪽은 opcode 를 하나씩 꺼내 실행하는 루프 자체가 기계입니다.

관련 항목

가상 머신에 관여하는 역할

게스트 · 호스트 · vCPU · 임베더

시스템 가상 머신을 구현하는 소프트웨어

하이퍼바이저 · KVM · 에뮬레이터

시스템 가상 머신이 특권 명령을 처리하는 방식

트랩과 에뮬레이션 · 하이퍼콜 · 반가상화 · 하드웨어 가상화 확장 · 중첩 가상화 · Intel VT-x · AMD-V

가상 머신이 성립하기 위한 요건

명령 집합 구조 · 메모리 영역 · 특권 명령

시스템 가상 머신을 조립하는 시스템 호출

ioctl · mmap · 파일 디스크립터 · 시스템콜 · apic

프로세스 가상 머신을 이루는 구성 요소

클래스 파일 · 명령어 집합 · opcode · 피연산자 스택 · 런타임 데이터 영역 · 프로그램 카운터 · 바이트코드

프로세스 가상 머신이 명령을 실행하는 방식

인터프리터 · JIT(Just-In-Time, 적시) 컴파일 · 스택 머신

프로세스 가상 머신의 하위 종류

Java 가상 머신 · WebAssembly · P-code

다른 이름: virtual machine · VM · 버추얼 머신