9. Segmentation
#세그먼트 #세그멘테이션
이전 8. Address Space에서 프로세스 주소공간을 베이스와 바운드 레지스터를 사용하여 배치하는 방법을 배웠다. 그런데 그림을 다시 보면 스택과 힙 사이에 사용되지 않는 큰 공간이 보인다. 이 공간은 낭비될 수 밖에 없을까? 이 점을 해결하기 위한 개념이 바로 세그멘테이션이다.
🔗 세그먼트
세그먼트의 목적은 주소공간을 물리적으로 연속적으로 하지 않겠다는 것이다. 세그먼트 조각으로 나누고 조각단위만 연속적이게끔 한다. 코드, 스택, 힙을 별도의 세그먼트로 정의하고 각 세그먼트끼리만 연속적이면 된다. 그러기 위해선 세그먼트 각각을 위한 베이스와 바운드 레지스터가 필요하다.
📌 세그먼테이션의 장점 1. 사용되는 메모리만 물리공간에 할당된다. 2. 주소공간이 큰 것을 효율적으로 재할당 할 수 있다.
왼쪽은 세그먼트 적용 전, 오른쪽은 적용 후다.
🔗 세그멘테이션 주소변환
아래의 예제로 가상주소에서 물리주소로 변환해 보자.
1. Fetch from address 100
코드 세그먼트의 100번지 이고 코드 세그먼트의 Base는 32K이다. 물리주소는 Base + Offset 이므로
32KB + 100 = 32868B
2. Load from address 4200
1번 처럼 34KB + 4200 라고 생각할 수 있지만, 힙은 가상주소에서 4KB부터 시작하기 때문에 Offset은 4200 - 4KB이다. 따라서
34KB + (4200 - 4KB) = 34KB + 104 = 34920B
3. Load from address 7KB
7KB는 세그먼트 밖에 존재한다. offset을 계산해도 3KB(7KB-4KB)이므로 세그먼트 사이즈를 넘어버린다. 따라서 세그먼트 폴트가 발생해 버린다.
🔗 세그먼트 종류 파악
위에서 주소변환 할때 변환할 가상주소가 힙인지, 스텍인지 어떻게 알 수 있을까? 가장 명확한 방법은 가상주소의 몇 비트를 세그먼트를 구분하기 위해 사용하는 것이다.예를들어 14비트중 상위 2비트를 사용한다면 가상주소모양은 다음과 같을 것이다.
상위 2비트가 00이면 코드, 01이면 힙, 10이면 스택.. 이런방식으로 표현할 수 있겠다.
🔗 스택
스택 세그먼트는 다른 세그먼트들과 반대로 방향이 확장된다. 그래서 주소변환을 다르게 해야한다. 각 세그먼트가 어느방향으로 자라는지, 방향에 대한 정보를 추가해야한다.
🔗 공유 지원
세그먼트의 장점을 살려서 세그먼트를 프로세스끼리 공유할수 있게 한다. 대신 Read-only로 읽기만 할 수 있다. 그런 세그먼트로는 코드가 있다.
스택과 공유자원을 포함한 세그먼트 레지스터 값을 나타낸 표이다.
세그먼트 | 베이스 | 크기 | 양수방향으로 증가? | 보호 |
---|---|---|---|---|
코드 | 32KB | 2KB | 1 | 읽기-실행 |
힙 | 34KB | 2KB | 1 | 읽기-쓰기 |
스택 | 28KB | 2KB | 0 | 읽기-쓰기 |
📌 Coarse-grained vs Fine-grained
지금까지 설명한 세그먼트는 대단위(coarse-grained)로 코드, 스택, 힙만을 지원했다. 하지만 이렇게 큰 단위로 공간을 분할하기보단 메모리공간을 더 잘게 쪼게는 fine-grained가 효율적일 수 도있다. 그런데 소단위로 관리하는 경우 모든 세그먼트마다 베이스, 바운드 레지스터가 필요하고 이를 관리하는 세그먼트 table을 또 관리해야하기 때문에 딱히 무엇이 좋다고 정확하게 말할 순 없다.
🔗 운영체제의 지원
세그멘테이션은 또 다른 새로운 문제를 제기한다.
- Context switch시에 세그먼트 레지스터를 잘 저장해야한다.
- 미사용 중인 물리메모리의 공간을 관리해야한다. (free-list관리)
- 가변적인 크기가 할당되면서 빈 공간의 크기가 다르고 메모리 할당 요청을 충족시키지 못하는 외부단편화문제가 발생한다.