Skip to content

OSTEP 16 Segmentation

Published: at 오후 11:29

OSTEP 16 Segmentation

지금까지 프로세스 주소 공간 전체를 메모리에 탑재하는 것을 가정해 왔다. 베이스와 바운드 레지스터를 사용하여 운영체제는 프로세스는 물리 메모리의 다른 부분으로 쉽게 재배치할 수 있었다

OSTEP 16 Segmentation-1689674323191.jpeg

하지만 프로그램의 힙과 스택 사이에 빈 공간이 사용되지 않더라도 주소 공간을 물리 메모리에 재배치할 때 메모리를 차지한다. 베이스와 바운드 레지스터 방식은 메모리 낭비가 심하다.

1. 세그멘테이션: 베이스/바운드의 일반화

이 아이디어는 MMU 안에 오직 하나의 베이스와 바운드 쌍만 존재하는 것이 아니라 주소 공간의 논리적인 세그먼트 마다 베이스와 바운드 쌍이 존재한다.

세그먼트: 특정 길이를 가지는 연속적인 주소 공간

우리가 기준으로 삼은 주소 공간에는 코드, 스택, 및 힙 세 종류의 세그먼트가 있다. 운영체제는 각 세그먼트를 물리 메모리의 각기 다른 위치에 배치할 수 있고, 사용되지 않는 가상 주소 공간이 물리 메모리를 차지하는 것을 방지할 수 있다.

OSTEP 16 Segmentation-1689674692978.jpeg

이 예제의 경우 3쌍의 베이스와 바운드 레지스터 집합이 필요하다.

OSTEP 16 Segmentation-1689674722721.jpeg

그림 19.1의 주소 공간을 사용하여 주소 변환을 해 보자. 가상 주소 100을 참조한다고 가정하자.

가상 주소 100번지는 코드 세그먼트에 속한다. 참조가 일어나면 하드웨어는 베이스 값에 이 세그먼트의 오프셋을 더해 물리 주소는 100 + 32KB = 32868이 된다. 그 후 주소가 범위(2KB) 내에 있는지 검사하고 범위 내에 있을 경우 물리 메모리 주소 32868을 얻는다.

가상 주소 4200의 힙을 사펴보자. 가상 주소 4200을 힙의 베이스 34KB에 더하는 방법을 잘못 된 방법이다. 힙 안에서의 오프셋, 즉 주소가 참조하는 바이트가 이 세그먼트 시작으로부터 몇 번째 바이트인지를 얻어야 한다. 힙은 가상 주소 4KB에서 시작하기 때문에 오프셋 4200은 4200 - 4096 = 104가 된다. 이 오프셋을 베이스 레지스터의 물리 주소 34KB에 더해 원하는 결과 34920을 얻게 된다.

만약 힙의 마지막을 벅어난 7KB와 같은 잘못된 주소를 접근하려고 한다면, 하드웨어가 주소 범위가 벗어났다는 사실을 감지하고 운영체제에 트랩을 발생시킨다. 운영체제는 아마 프로세스를 종료시킬 것이고 이것이 Segment Fault이다.

2. 세그먼트 종류의 파악

하드웨어는 변환을 위해 세그먼트 레지스터를 사용한다. 하드웨어는 가상 주소가 어느 세그먼트를 참조하는지, 그리고 그 세그먼트 안에서 오프셋은 얼마인지를 어떻게 알 수 있을까?

방법 1: 가상 주소의 최상위 몇 비트를 기준으로 주소 공간을 여러 세그먼트로 나누기.

위의 예시에서는 3개의 세그먼트가 있었다. 주소 공간을 세그먼트로 나누기 위해서는 2비트가 필요하다.

최상위 2비트가 00이면 가상 주소가 코드 세그먼트를 가리킨다 최상위 2비트가 01이면 가상 주소가 힙 세그먼트를 가리킨다 …

OSTEP 16 Segmentation-1689675668694.jpeg

3. 스택

스택은 다른 세그먼트들과는 다르게 반대 방향으로 확장된다. 따라서 다른 방식의 변환이 필요하다. 간단한 하드웨어가 추가로 필요하다. 세그먼트가 어느 방향으로 확장하는지도 알아야 한다. 하나의 비트를 사용하여 주소가 커지는 방향으로 확장하면 1, 작아지는 방향으로 확장하면 0으로 설정할 수 있다.

OSTEP 16 Segmentation-1689675870887.jpeg

4. 공유 지원

메모리를 절약하기 위해 주소 공간들 간에 특정 메모리 세그먼트를 공유하도록 할 수 있다. 이를 위해 하드웨어에 protection bit의 추가가 필요하다.

세그먼트를 읽거나 쓸 수 있는지 / 세그먼트의 코드를 실행시킬 수 있는지

OSTEP 16 Segmentation-1689676095627.jpeg

이렇게 하면 주소 공간의 독립성을 유지하면서도, 여러 프로세스가 주소 공간의 일부를 공유할 수 있다. 각 프로세스는 여전히 자신의 전용 메모리를 사용하고 있다고 생각한다.

가상 주소가 범위 내에 있는지 확인하는 것에 더해, 특정 액세스가 허용되는지를 확인하도록 알고리즘을 수정해야 한다. 허용되지 않은 액세스를 시도하는 경우, 하드웨어는 예외를 발생시킨다.

5. 소단위 대 대단위 세그먼테이션

지금까지 예제는 소수의 세그먼트(코드, 스택, 힙)만을 지원하는 시스템에 초점을 맞추었다. 이 세그먼테이션을 대단위 (coarse-grained) 라고 생각할 수 있다. 일부 초기 시스템은 더 작은 단위로 주소 공간을 나누는 것이 허용되었다. 이를 소단위 (fine-grained) 세그먼테이션이라고 부른다. 많은 수의 세그먼트를 지원하기 위해 세그먼트 테이블같은 하드웨어를 따로 두었다.

6. 운영체제의 지원

스택과 힙 사이의 사용하지 않는 공간에 물리 메모리를 할당할 필요가 없어졌다. 따라서 같은 크기의 물리 메모리에 더 많은 주소 공간을 탑재할 수 있게 되었다.

문맥 교환 시 운영체제는 어떤 일을 해야 할까?

세그먼트 레지스터의 저장과 복원이 필요하다. 프로세스가 다시 실행되기 전에 레지스터들을 올바르게 설정해야 한다.

각 세그먼트의 크기가 다를 수 있기 때문에 딱 맞게 주소를 할당할 수 없다. 미사용 중인 물리 메모리 공간의 관리는 어떻게 해야 할까?(외부 단편화 문제)

OSTEP 16 Segmentation-1689676700351.jpeg

기존의 세그먼트를 정리하여 물리 메모리를 압축한다. 프로세스를 중단하고 그들의 데이터를 하나의 연속된 공간에 복사하고, 세그먼트 레지스터가 새로운 물리 주소를 가리키게 한다.

세그먼트 복사는 메모리에 부하가 큰 연산이다. 비용이 많이 드는 압축 말고 다른 방법은 없을까?

빈 공간 리스트를 관리하는 알고리즘을 사용한다. best-fit, worst-fit, buddy-algorithm 등 여러 가지 알고리즘이 존재한다. best-fit 알고리즘은 빈 공간 리스트에서 요청된 크기와 가장 비슷한 크기의 공간을 할당하는 알고리즘이다.