*이 글은 Operating Systems: Three Easy Pieces(운영체제 아주 쉬운 세 가지 이야기)를 바탕으로 작성되었습니다. 첨부한 모든 그림은 해당 도서에서 가져온 자료입니다. 내용 중 잘못된 부분이 있다면 알려주세요 :)
Dynamic allocation은 heap, stack 사이의 공간이 낭비되는 내부 단편화 문제가 있었다.
이를 방지하기 위해 만들어진 segment에 대해 알아보자!
🧐 Segment란
Address Space는 Code, Heap, Stack 영역 등으로 구성되어있다. 이 각각의 영역을 세그먼트(Segment)라고 한다.
다시 말해, 세그먼트은 특정 길이를 가지는 연속적인 주소 공간이다.
우리가 기존에 공부했던 base, bound를 생각해보자(맨 위 그림 참고)
프로세스들은 각각 한 쌍의 base, bound를 갖는다.
이젠 세그먼트마다 한 쌍의 base, bound를 갖도록 하자.
OS는 각 세그먼트를 물리 메모리 상에서 다른 위치에 배치할 수 있고, 낭비되는 공간을 방지할 수 있다.
세그먼트를 지원하는 경우에 주소 변환을 해보자.
우선 Code 영역부터 살펴보자.
virtual address 100번지를 참조한다고 가정하자.
physical address = 100 + 32KB
(100은 2KB보다 작기 때문에 범위 내에 존재)
Heap영역을 살펴보자
virtual address 4200번지를 참조한다고 가정하자.
physical address = 4200 + 34KB
위처럼 계산하면 어떻게 될까? heap 영역을 벗어나버린다.
모든 세그먼트가 각각 base, bound 값을 갖기 때문에, 이전처럼 주소 변환을 하면 안된다.
physical address = offset + base
offset = virtual address - start virtual address of segment
가상 주소에서 실제 해당 세그먼트의 시작 지점을 뺀 offset 값을 더해야한다.
그렇다면 heap 영역의 physical address = (4200 - 4096) + 34KB이다.
마지막으로 Stack 영역을 살펴보자.
stack은 Code, Heap 영역과 반대 방향으로 늘어날 수 있다. 이 때문에 다른 방식의 변환이 필요하다.
base, bound값 뿐만 아니라, 어떤 방향으로 확장하는지도 알아야한다.
이 정보를 반영하여 하드웨어가 주소 변환을 수행해야한다.
그렇다면 하드웨어는 어떻게 주소 변환을 하는걸까?
🧐 세그먼트 종류 파악
하드웨어는 주소 변환을 수행한다.
세그먼트를 사용하여 주소 변환 시,
- heap, code, stack 중 어떤 세그먼트를 참조하는지
- offset은 얼마인지
하드웨어가 어떻게 알 수 있을까?
일반적인 방법은 위 그림과 같이 가상 주소의 최상위 몇 비트를 기준으로 주소 공간을 여러 세그먼트로 나누는 것이다.
-> 최상위 2비트에 세그먼트 표시
-> 나머지 offset 표시
예시를 보자
최상위 2비트가 01이면 힙 세그먼트에 해당한다.
하위 12비트는 0000 0110 1000 또는 10진수로 104이다.
이를 통해 physical address = 104 + heap base 임을 알 수 있다.
( offset < bound도 검사해야한다.)
이 작업을 코드로도 살펴보자.
// get top 2 bits of 14-bit VA
Segment = (VirtualAddress & SEG_MASK) >> SEG_SHIFT
// now get offset
Offset = VirtualAddress & OFFSET_MASK
if (Offset >= Bounds[Segment])
RaiseException(PROTECTION_FAULT)
else
PhysAddr = Base[Segment] + Offset
Register = AccessMemory(PhysAddr)
위의 코드의 상수 값들을 정할 수 있다.
`SEG_MASK` = 0x3000(11000000000000)
`SEG_SHIFT` = 12
`OFFSET_MASK` = 0xFFF (00111111111111)
그렇다면 위에서 말한 Stack 영역에 대해 이어서 이야기 해보자.
virtual address 15KB를 참조한다고 가정한다.
15KB는 (15 x 2**10)byte로(메모리 한 칸은 1byte 크기), 이를 이진 형태로 변환하면 11 1100 0000 0000
아래 그림과 같이 나타낼 수 있다.
offset = 3KB
음수 오프셋을 얻기 위해선 3KB에서 세그먼트 최대 크기를 빼야한다.
세그먼트 최대 크기 = 4KB (12bit offset)
Correct negative offset = 3KB - 4KB = -1KB
physical address = 28KB - 1KB = 27KB
(abs(offset) < bound)
🧐 공유 지원
메모리를 절약하기 위해 주소 공간들 간에 특정 메모리 세그먼트를 공유할 수 있다.
공유 지원을 위해, 하드웨어에 protection bit의 추가가 필요하다.
protection bit는 읽기, 쓰기, 실행 가능 여부를 나타낸다.
코드 세그먼트는 읽기 및 실행으로 설정되어, 같은 물리 세그먼트가 여러 가상 주소 공간에 매핑될 수 있다.
🧐 segmentation의 Pros & Cons
Pros
- 주소 공간 사이의 공간 낭비를 방지한다.
- 빠르고 쉽고, 하드웨어 구현에 적합하다.
- 코드 공유가 가능하다.
- 각 세그먼트에 동적 할당을 지원한다.
Cons
- 외부 단편화 (External fragmentation)
- 지금까지 주소 공간의 크기가 일정하다고 가정했지만, 실제론 프로세스가 많은 세그먼트를 가질 수 있고 각 세그먼트는 크기가 다를 수 있다.
- 위와 같은 경우 물리 메모리에 빠르게 작은 크기의 빈 공간이 채워진다. 이 때문에 세그먼트 할당, 확장에 힘들어진다.
- 이를 외부 단편화 문제라고 부른다.
- 세그먼트 압축 costly
- 외부 단편화 문제를 해결하기 위해 물리 메모리는 압축할 수 있다.
- 하지만, 세그먼트 압축은 비용이 많이 든다.
- 세그먼트는 flexible하지 않다.
- 크기가 크지만 드물게 사용되는 힙이 하나의 논리적인 세그먼트에 배정되어 있다고 할 때 이 힙에 접근하기 위해서는 힙 전체가 물리 메모리에 존재해야 한다.
이번 시간엔 segment에 대해 배웠다.
세그먼트는 Heap, stack 사이의 낭비되는 공간 문제를 해결하기 위한 방법이지만,
외부 단편화 문제가 있다. 다음 글엔 이를 해결할 방법을 소개하도록 하겠다.
↯ 다음글 ↯
'기본 > 운영체제' 카테고리의 다른 글
[OS] CPU 가상화 (CPU Virtualization): 1. 프로세스란 (1) | 2024.04.20 |
---|---|
[OS] 메모리 가상화(Memory Virtualization): 5. Paging: 개요 (1) | 2024.04.20 |
[OS] 메모리 가상화(Memory Virtualization): 4. Free-Space Management (0) | 2024.04.19 |
[OS] 메모리 가상화 (Memory Virtualization): 2. Address translation (0) | 2024.04.11 |
[OS] 메모리 가상화 (Memory Virtualization): 1. 메모리 가상화의 시작 (2) | 2024.04.09 |