개발 공부

손승열(Son Seungyeol)

[운영체제][OSTEP] 주소 공간의 개념

주소 공간의 개념에 대해 공부해봅니다.

손승열(Son Seungyeol)
[운영체제][OSTEP] 주소 공간의 개념

1️⃣ 초기 시스템

메모리 관점에서 초기 컴퓨터는 많은 개념을 사용자에게 제공하지 않았음.

운영체제 초기 컴퓨터의 물리 메모리는 다음과 같이 생겼었다.

 0 KB ┌──────────────────────┐
      │   Operating System   │
      │  (code, data, etc.)  │
64 KB ├──────────────────────┤
      │                      │
      │                      │
      │                      │
      │                      │
      │   Current Program    │
      │  (code, data, etc.)  │
      │                      │
      │                      │
      │                      │
  max └──────────────────────┘

운영체제는 메모리(위의 예에서는 물리 주소 0부터)에 상주하는 루틴(실제로는 라이브러리)의 집합이었음.

물리 메모리에 하나의 실행 중인 프로그램(프로세스)이 존재(위의 예에서는 물리 주소 64KB부터 시작)하여 나머지 메모리를 사용하였음.

특별한 가상화는 거의 존재하지 않았고 사용자는 운영체제로부터 많은 것을 기대하지 않았음.


2️⃣ 멀티프로그래밍과 시분할

컴퓨터는 고가 장비였었음 ➡️ 사람들이 더 효과적으로 컴퓨터를 공유하기 시작
➡️ 멀티프로그래밍(multi-programming) 시대가 도래

여러 프로세스가 실행 준비 상태에 있고 운영체제는 그들을 전환하면서 실행
➡️ 한 프로세스가 I/O를 실행하면, CPU는 다른 프로세스로 전환
➡️ CPU의 이용률 증가

당시에는 특히 이러한 효율성의 개선이 중요했었음.

사람들이 컴퓨터를 더 많이 사용하길 원하기 시작
➡️ 시분할(time-sharing) 시대가 시작

많은 사람들이 일괄처리방식(batch computing) 컴퓨팅의 한계를 인식

많은 사용자가 동시에 컴퓨터를 사용 & 현재 실행 중인 작업으로부터 즉시 응답을 원함.
➡️ 대화식 이용(interactivity)의 개념이 중요해짐.

시분할을 구현하는 한 가지 방법: 하나의 프로세스를 짧은 시간 동안 실행

이 방법에서는 프로세스 중단 시, 중단 시점의 모든 상태를 디스크(1️⃣의 형태)에 저장해야 했다.

위 방법에는 커다란 문제가 있음.

너무 느리게 동작하고, 특히 메모리가 커질수록 느리게 됨.
➡️ 레지스터 상태를 저장하고 복원하는 것은 빠르지만 메모리의 내용 전체를 디스크에 저장하는 것은 매우 느림.

우리의 목표: 프로세스 전환 시 프로세스를 메모리에 그대로 유지하면서, 운영체제가 시분할 시스템을 효율적으로 구현할 수 있게 하는 것

다음은 세 개의 프로세스가 실행될 때, 이러한 목표 달성을 위한 공유 메모리의 모습을 나타낸 것이다.

  0 KB ┌──────────────────────┐
       │   Operating System   │
       │  (code, data, etc.)  │
 64 KB ├──────────────────────┤
       │        (free)        │
       │                      │
128 KB ├──────────────────────┤
       │      Process C       │
       │  (code, data, etc.)  │
192 KB ├──────────────────────┤
       │      Process B       │
       │  (code, data, etc.)  │
256 KB ├──────────────────────┤
       │        (free)        │
       │                      │
320 KB ├──────────────────────┤
       │      Process A       │
       │  (code, data, etc.)  │
384 KB ├──────────────────────┤
       │        (free)        │
       │                      │
448 KB ├──────────────────────┤
       │        (free)        │
       │                      │
512 KB └──────────────────────┘

시분할 시스템의 대중화 ➡️ 운영체제에게 새로운 요구 사항이 부과

여러 프로그램이 메모리에 동시에 존재하려면 보호(protection)가 중요한 문제가 됨.
➡️ 한 프로세스가 다른 프로세스의 메모리를 읽거나 더 안 좋게 쓰는 상황을 피해야 함.


3️⃣ 주소 공간

운영체제는 위와 같은 위험(한 사용자)에 대비하여 사용하기 쉬운(easy to use) 메모리 개념을 만들어야 한다.

이 개념이 주소 공간(address space)이다.
➡️ 실행 중인 프로그램이 가정하는 메모리의 모습

운영체제의 메모리 개념을 이해하는 것 = 메모리를 어떻게 가상화할지 이해하는 것

주소 공간은 실행 프로그램의 모든 메모리 상태를 갖고 있다.
➡️ 예를 들어, 프로그램의 코드(code, 명령어)는 반드시 메모리에 존재해야 함 ➡️ 따라서 주소 공간에 존재

스택(stack)함수 호출 체인 상의 현재 위치, 지역 변수, 함수 인자와 반환 값 등을 저장하는 데 사용

힙(heap)은 동적으로 할당되는 메모리를 위해 사용
➡️ C 언어의 malloc(), C++ 또는 Java 같은 객체 지향 언어의 new를 통해 메모리를 동적으로 할당받음.

기타 사항을 제외하고 코드, 스택 및 힙의 세 가지만 고려했을 때, 주소 공간의 모습은 다음과 같다.

 0 KB ┌──────────────────────┐
      │     Program Code     │
 1 KB ├──────────────────────┤
      │         Heap         │
 2 KB ├──────────────────────┤
      │          │           │
      │          │           │
      │          │           │
      │          ↓           │
      │        (free)        │
      │          ↑           │
      │          │           │
      │          │           │
      │          │           │
15 KB ├──────────────────────┤
      │        Stack         │
16 KB └──────────────────────┘

프로그램 코드는 주소 공간의 위쪽에 위치한다.(위의 예에서는 주소 0부터 시작하여 1KB를 차지)
➡️ 코드는 정적이기 때문에 메모리에 저장하기 쉬움.
➡️ 따라서 주소 공간의 상단에 배치(프로그램 실행 시 추가 메모리 필요X)

프로그램 실행과 더불어 확장되거나 축소될 수 있는 두 종류의 주소 공간이 존재
➡️ 주소 공간의 상단에 존재하는 힙과 하단에 존재하는 스택
➡️ 두 영역은 확장 가능해야 하고, 주소 공간의 양 끝단에 배치해야 두 영역 모두 확장 가능하므로 이와 같이 배치

위의 예에서 힙은 코드 바로 뒤 1KB부터 시작하여 아래 방향으로 확장
➡️ 사용자가 malloc() 함수를 통해 더 많은 메모리를 요청하는 경우 등

위의 예에서 스택은 16KB에서 시작하여 위쪽 방향으로 확장
➡️ 사용자가 프로시저를 호출하는 경우 등

스택과 힙의 이러한 배치는 관례일 뿐이다.
➡️ 다른 방식으로도 배치 가능
⚠️ 주소 공간에 여러 쓰레드가 공존할 때는 다른 방식으로 주소 공간을 나눌 때 동작하지 않음. (관례대로 해야됨.)

주소 공간을 설명할 때, 운영체제가 실행 중인 프로그램에게 제공하는 개념(abstraction)을 설명한다.
➡️ 실제로 프로그램이 물리 주소 0에서 16KB 사이에 존재하는 것은 아님.
➡️ 실제로는 임의의 물리 주소에 탑재됨.(2️⃣의 예시 참고)

⭐ 우리의 문제: 메모리를 어떻게 가상화하는가?

운영체제가 이 일을 할 때, 우리는 운영체제가 메모리를 가상화(virtualizing memory)한다고 말한다.

예를 들어, 2️⃣의 예시에서 프로세스 A가 주소 0(가상 주소(virtual address))으로부터 load 연산을 수행할 때, 운영체제는 실제 물리 주소인 320KB(A가 탑재된 메모리)를 읽도록 보장해야함.
➡️ 메모리 가상화의 열쇠 & 현대 모든 컴퓨터 시스템의 기저

가상 주소(virtual address)

C 프로그램에서 포인터 출력 시 나오는 값은 가상 주소이다.
➡️ 사용자 프로그램(user level program)이 볼 수 있는 주소는 모두 가상 주소

메모리 가상화의 기술 때문에, 물리 메모리 주소를 알 수 있는 것은 오직 운영체제뿐임.

저장된 실제 물리 메모리 위치에서 값을 반입하기 위해 운영체제와 하드웨어에 의해 가상 주소가 물리 주소로 변환됨.


4️⃣ 목표

운영체제가 가상화(가상 메모리 시스템(VM))를 해내기 위해 필요한 몇 가지 목표를 살펴보자.

투명성(transparency)

운영체제는 실행 중인 프로그램이 가상 메모리의 존재를 인지하지 못하도록 가상 메모리 시스템을 구현해야 함.

많은 작업들이 메모리를 공유할 수 있도록 운영체제와 하드웨어가 모든 작업을 수행

효율성(efficiency)

운영체제는 가상화가 시간과 공간 측면에서 효율적이도록 해야 함.

🚫 프로그램의 느린 실행
🚫 가상화 지원을 위한 구조에 너무 많은 메모리 사용

시간-효율적인 가상화를 구현할 때, 운영체제는 TLB 등의 하드웨어 기능을 포함한 하드웨어의 지원을 받아야 함.

보호(protection)

운영체제는 프로세스를 다른 프로세스로부터 보호해야 하고 운영체제 자신도 프로세스로부터 보호해야 함.

프로세스가 탑재, 저장, 명령어 반입 등을 실행할 때 어떤 방법으로든 다른 프로세스나 운영체제의 메모리 내용에 접근하거나 영향을 줄 수 있어서는 안 됨.
➡️ 프로세스는 자신의 주소 공간 밖의 어느 것도 접근할 수 있어서는 안 됨.

보호 성질을 이용하여 프로세스들을 서로 고립(isolate)시킬 수 있음.


📚 참고 문헌

Operating Systems: Three Easy Pieces ― 13: The Abstraction: Address Spaces

운영체제 아주 쉬운 세 가지 이야기 ― 16: 주소 공간의 개념

관련있는 게시물


Made with React, Gatsby and DatoCMS by @smastrom

Contribute or star on GitHub

© 2022-2023 손승열 for 🅒🅞🅝🅣🅔🅝🅣🅢

모두 좋은 하루 보내세요! 😊