Home

Published

- 14 min read

[ OS ] 6. Address Space, Address Translation

img of [ OS ] 6. Address Space, Address Translation

주소공간(Address Space)

실제 메모리에 프로세스의 자원을 할당하는 경우를 생각해보자. 한 프로세스가 다른 프로세스의 메모리를 읽거나, 안 좋게 쓸 수 있는 상황이 있을 수 있다. 이런 위험한 상황을 대비하여 운영체제는 사용하기 쉬운 메모리 개념을 만든다. 이 개념이 주소 공간(Address Space)이다. 주소공간은 실행 프로그램의 모든 메모리 상태를 갖고 있다.

예를 들어, 프로그램의 코드(code, 명령어)는 반드시 메모리에 존재해야 한다. 따라서 주소 공간에 위치한다. 스택은 함수 호출 체인 상의 현재 위치, 지역 변수, 함수 인자와 반환 값 등을 저장하는 데 사용된다. 힙(heap)은 동적으로 할당되는 메모리를 위해 사용된다. C언어의 malloc(), C++이나 Java 같은 객체 지향 언어의 new를 통해 메모리를 동적으로 할당받는다.

Address Space

위 그림은 아주 작은 주소공간을 보이고 있다. 프로그램 코드는 주소 공간의 위쪽에 위치한다. 이 예제에서는 주소 0부터 시작하고, 주소 공간의 첫 1KB를 차지한다. 코드는 정적이기 때문에 메모리에 저장하기 쉽다. 따라서 주소공간의 상단에 배치하고, 프로그램이 실행되면서 추가 메모리를 필요로 하지 않는다.

다름으로는 프로그램의 실행과 더불어 확장되거나 축소될 수 있는 두 종류의 주소 공간이 존재한다. 주소 공간의 상단에 존재하는 힙과 하단에 존재하는 스택이다. 두 메모리 영역은 확장할 수 있어야 하기 때문에 이런 방식으로 배치하고, 주소 공간의 양 끝단에 배치해야 두 영역 모두 확장하는 것이 가능하다.

두 영역은 확장 방향이 반대이다. 힙은 코드 바로 뒤 1KB부터 시작하고 아래쪽으로 확장한다. 스택은 16KB에서 시작하고 위쪽 방향으로 확장한다. 하지만 이런 방법은 관례여서 원하면 다른 방식으로 해도 된다.(주소공간을 다른 방식으로 배치)

가상 메모리 시스템(VM)의 주요 목표

투명성(transparency)

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

사용자나 응용 프로그램이 가상 메모리 시스템의 존재를 인지하지 못하도록 하는 것은 시스템의 사용을 간편하게 만든다. 응용 프로그램은 물리적 메모리와 상호 작용하는 대신, 자신이 사용하는 메모리 공간을 가상 메모리로 인식할 수 있다. 이것은 시스템을 유연하게 만들며, 응용 프로그램의 개발과 관리를 단순화시킨다. 또한, 시스템의 물리적 메모리 구조를 변경하더라도 응용 프로그램에 영향을 미치지 않고 가상 메모리 시스템을 조정할 수 있다.

효율성(efficiency)

운영체제는 가상화가 시간과 공간 측면에서 효율적이여야 한다.

가상 메모리 시스템은 시간과 공간 측면에서 효율적이어야 한다. 이는 시스템의 성능을 향상시키고 자원의 낭비를 최소화하는 데 도움이 된다. 시간적 효율성은 가상 메모리 시스템이 메모리 액세스를 빠르게 처리하고, 응용 프로그램의 반응 시간을 최소화하는 데 중요하다. 공간적 효율성은 물리적 메모리를 효율적으로 활용하여 시스템 전체적으로 자원을 효율적으로 관리하는 것을 의미한다.

보호(protection)

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

이는 다른 프로세스가 프로세스의 메모리 공간을 침범하지 못하도록 하는 것을 의미한다. 또한, 운영체제는 자신의 메모리 영역을 보호하여 시스템의 안정성을 유지하고, 악의적인 프로그램이 시스템에 피해를 입히는 것을 방지한다. 보호 기능은 시스템의 안전성과 신뢰성을 유지하는 데 필수적이다.

**당신이 보는 모든 주소는 가상 주소이다.**포인터를 출력하는 C프로그램을 작성해본적이 있는가. 당신이 보는 값은 가상주소이다. 프로그램 코드가 탑재된 주소가 어디인지 출력할 수는 있다. 하지만 그건 가상주소다. 메모리 가상화의 기술 때문에, 명령어와 데이터가 탑재되어 있는 물리 메모리 주소를 알 수 있는 것은 운영체제뿐이다.

주소 변환의 원리

효율적이고 유연하게 메모리를 가상화하기 위해서 어떻게 해야 할까? 우리는 하드웨어 기반 주소 변환(hardware-based address translation) 또는 그냥 짧게 주소 변환(address translation)이라는 기법을 사용한다.

이 기술은 제한적 직접 실행 방식에 부가적으로 사용되는 기능이라고 생각할 수 있다. 주소 변환을 통해 하드웨어는 명령어 반입, 탑재, 저장 등의 가상 주소를 정보가 실제 존재하는 물리주소로 변환한다. 프로그램의 모든 메모리 참조를 실제 메모리 위치로 재지정하기 위하여 하드웨어가 주소를 변환한다.

하드웨어에서 제공하는 저수준(Low level) 기능들은 변환을 가속화시키는 도움을 준다. 하지만 하드웨어만으로 메모리 가상화를 구현할 수는 없다. 따라서 운영체제가 관여하여 정확한 변환이 일어날수 있도록 하드웨어를 셋업한다. 운영체제는 메모리의 빈 공간과 사용중인 공간을 항상 알고 있어야 하고, 메모리 사용을 제어하고 관리한다.

동적(하드웨어 기반) 재배치

Address Translation

각 CPU마다 2개의 하드웨어 레지스터가 필요하다. 하나는 베이스(base) 레지스터라고 불리고, 다른 하나는 바운드(bound) 레지스터 혹은 한계(limit) 레지스터라고 불린다. 이 베이스와 바운드 레지스터 쌍은 우리가 원하는 위치에 주소공간을 위치할 수 있게 한다. 배치와 동시에 프로세스가 오직 자신의 주소공간에만 접근한다는 것을 보장한다.

이 설정에서 각 프로그램은 주소 0에 탑재되는 것처럼 작성되고 컴파일된다. 프로그램 시작시, 운영체제가 프로그램이 탑재될 물리 메모리 위치를 결정하고 베이스 레지스터를 그 주소로 지정한다. 프로세스가 실행되면, 프로세스에 의해 생성되는 모든 주소가 다음과 같은 방법으로 프로세서에 의해 변환된다.

   physical address = virtual address + base

프로세스가 생성하는 메모리 참조는 가상주소이다. 하드웨어는 베이스 레지스터의 내용을 이 주소에 더하여 물리 주소를 생성한다.

다음 예시 코드를 통해 명령어가 실행될 떄 어떤 일이 일어나는지 살펴보자.

   128: mov1 oxo(%EBX), % eax

프로그램 카운터(PC는 128로 설정된다. 하드웨어가 이 명령어를 반입할 때, 먼저 PC값을 베이스 레지스터의 값 32KB(32768)에 더해 32896의 물리 주소를 얻는다. 그 후, 하드웨어는 더한 물리주소에서 명령어를 가져온다. 그리고 프로세서는 명령어의 실행을 시작한다. 얼마 후 프로세스는 가상 주소 15KB의 값을 탑재하라는 명령어를 내린다. 이 주소를 프로세서가 받아 다시 베이스 레지스터(32KB)를 더하고 물리주소 47KB에서 원하는 내용을 탑재한다.

이 기술을 가상주소에서 물리주소로의 변환, 주소변환이라고 부른다. 하드웨어는 프로세스가 참조하는 가상 주소를 받아들여 데이터가 실제로 존재하는 물리주소로 변환한다. 이 주소의 재배치는 실행 시에 일어나고, 프로세스가 실행을 시작한 이후에도 주소공간을 이동할 수 있기 때문에, 동적 재배치(dynamic relocation)이라고도 불린다.

바운드 레지스터는 보호를 지원하기 위해 존재한다. 프로세서는 먼저 메모리 참조가 합법적인가를 확인하기 위해 가상 주소가 바운드 안에 있는지 확인한다. 프로세서는 먼저 메모리 참조가 합법적인가를 확인하기 위해 가상 주소가 바운드 안에 있는지 확인한다. 바운드의 요점은 프로세스가 생성한 모든 주소가 합법적이고 프로세스의 “범위”에 있다는 것을 확인하는 것이다.

바운드 레지스터는 두가지 방식중 하나로 정의될 수 있다. 한 가지 방법은 앞에서처럼 주소 공간의 크기를 저장하는 방식으로 하드웨어는 가상 주소를 베이스 레지스터에 더하기 전에 먼저 바운드 레지스터와 비교한다. 두번째 방식은 주소 공간의 마지막 물리 주소를 저장하는 방식으로 하드웨어는 먼저 베이스 레지스터를 더하고 그 결과가 바운드 안에 있는지 검사한다.