운영체제 아주 쉬운 세가지 이야기 책에 대한 스터디를 진행한다.
이 글에서는 가상화에 대해 다룬 1장부터 2장까지의 내용을 정리한다.
1장. 이 책에 관한 대화
이 책에서는 운영체제의 세부 주제 중
다음 세 개의 주제와 이와 관련하여 운영체제의 동작에 대해 소개한다.
- 가상화
- 병행성
- 영속성
2장. 운영체제 개요
프로그램은 명령어를 초당 수백만 번 반입(fetch), 해석(decode), 실행(execute) 한다.
이러한 프로그램을 쉽게 실행, 프로그램 간 메모리 공유, 장치와 상호작용을 도와주는 등 다양한 일을 하는 소프트웨어가 바로 운영체제(operating system, OS) 다.
위와 같은 일을 하기 위해 운영체제는 물리적인 자원을 가상 형태의 자원을 생성한다. 이 기법을 가상화(vitualization) 라고 하며, 이러한 이유로 가상 머신(virtual machine)이라고 불리기도 한다. 가상화를 통해 프로그램들이 CPU 를 공유하여, 동시에 실행하고 각자 명령어와 데이터를 접근할 수 있게 한다. 이러한 이유로 운영체제를 자원 관리자(resource manager) 라고도 한다.
프로그램 실행, 메모리 할당, 파일 접근 같은 가상 머신과 관련된 요청을 처리하기 위해 운영체제에서 시스템 콜을 제공한다.
2.1장 CPU 가상화
운영체제가 CPU 를 무한 개의 CPU 가 존재하는 것처럼 환상(illusion)을 만들어 여러 프로그램을 실행하는 것을 CPU 가상화(virtualizing the CPU)라고 한다.
여러 프로그램 중 실행되는 프로그램을 정하는 것은 운영체제 정책(policy)에 따라 달라진다.
2.2 메모리 가상화
컴퓨터에서의 물리 메모리(physical memory) 모델은 바이트 배열로 사용하기 위해서는 주소(address)와 데이터가 필요하다.
물리 메모리 공간은 공유 자원이지만 한 프로그램의 메모리 연산은 다른 프로그램의 주소 공간에 영향을 주지 않는다.
운영체제가 메모리 가상화(virtualizing memory) 를 하기 때문인데,
이로 인해 각 프로세스는 자신만의 가상 주소 공간(virtual address space) 가지게 된다.
운영체제는 이 가상 주소 공간을 컴퓨터의 물리 메모리로 매핑을 해준다.
2.3 병행성
병행성(concurrency) 은 프로그램이 한 번에 많은 일을 할 때 발생되는 문제들을 가리킬 때 사용된다.
병행성 문제는 운영체제 뿐만 아니라 멀티 쓰레드 프로그램에도 동일하게 발생된다.
멀티 쓰레드 프로그램에서 각 쓰레드가 공유하고 있는 값을 동시에 변경하려고 한다면 예상치 못한 결과가 나올 것이다.
이러한 이유는 레지스터 탑재, 레지스터 값 계산, 레지스터 값을 다시 메모리에 저장하는 등의
명령어가 원자적(atomically) 으로(한 번에 모두) 실행되지 않기 때문에 발생된다.
2.4 영속성
DRAM 과 같은 장치는 휘발성(volatile) 방식으로 저장하기 때문에 고장나거나 전원이 꺼지면 데이터가 손실된다.
데이터를 영속적 저장하기 위해서는 하드웨어와 소프트웨어가 필요하다.
- 하드웨어 (입력/출력 혹은 I/O 장치형태로 제공)
- SSD(solid-state drives)
- 하드 드라이브(hard drive)
- 소프트웨어
- 파일 시스템(file system)
- 디스크 관리 용도
- 응용프로그램들이 요청한 쓰기 요청을 모아서 한번에 처리 (성능 향상)
- 요청 내용이 기록되기 전에 손실되지 않도록 저널링(journaling) 이나 쓰기-시-복사(Copy-On-Write) 기법 사용 (쓰기 명령들 간에 기록 순서 강제 보장)
- 파일 시스템(file system)
2.5 설계 목표
운영체제의 역할은 간단하게 정리하면 다음과 같다.
- CPU, 메모리, 디스크와 같은 물리 자원을 가상화(virtualize)
- 병행성 문제 처리
- 파일을 영속적으로 저장
이런 시스템을 구현하기 위해서는 몇 가지 목표가 필요하다.
- 시스템을 편리하고 사용하기 쉽게 만드는 데 필요한 개념(abstraction)들 정의
- 추상화를 통해 큰 프로그램을 이해하기 쉽게 나누어 구현 가능
- 오버헤드를 최소화(minimize the overhead)
- 시간이나 공간을 최소로 하는 해결책을 찾음
- 운영체제와 응용 프로그램 간의 보호
- 프로그램의 악의적이거나 의도치 않은 행위를 피해주지 않는 것을 보장
- 프로세스를 다른 프로세스로부터 고립(isolation)
- 운영체제는 계속 실행되어야 함
- 운영체제가 실패하면 모든 응용프로그램도 실패하게 되므로 높은 수준의 신뢰성(reliability) 제공
- 이외에도 에너지-효율성(energy-efficiency), 보안(security), 이동성(mobility) 목표를 지향
2.6 배경 소개
초창기 운영체제: 단순 라이브러리
초창기에는 기본적으로 자주 사용되는 함수들을 모아 놓은 라이브러리
작업들이 준비되면 컴퓨터 관리자가 일괄 처리(batch) 진행
라이브러리를 넘어서 보호
운영체제를 파일 시스템과 같은 라이브러리 형태로 구현하면 모든 응용프로그램이 디스크를 읽을 수 있기 때문에 개인정보 보호가 불가능하다.
이 방안으로 시스템 콜이라는 기능이 발명되었다.
운영체제와 일반 라이브러리가 구분되어 운영체제 코드를 실행하기 위해서는 정해직 규칙에 따라 제어 가능한 과정을 거치게 된다.
시스템 콜은 운영체제에게 제어를 넘기기 때문에 하드웨어 특권 수준(hardware privilege level) 을 상향 조정한다.
사용자 응용 프로그램은 사용자 모드(user mode) 상태에서 실행되며, 시스템 콜은 trap 이라는 하드웨어 명령어를 이용해 호출한다.
하드웨어는 트랩 핸들러(trap handler) 함수에게 제어권을 넘기고 커널 모드(kernel mode) 로 격상시킨다.
커널 모드에서는 하드웨어를 자유롭게 접근할 수 있으며, 서비스를 완료하면 return-from-trap 특수 명령어로 제어권을 다시 사용자에게 넘긴다.
멀티프로그래밍 시대
컴퓨터 자원을 효율적으로 활용하기 위해 멀티프로그래밍(multiprogramming) 기법이 대중화 되었다.
멀티프로그래밍을 활용하면서 메모리 보호 문제(memory protection)가 발생하게 됐고 병행성(concurrency) 문제에 대한 이해가 중요하다.