Search

메모리

OS에서의 메모리

메모리 : 주소가 할당된 일련의 바이트들로 구성
메모리는 주소(address)와 데이터(data)로 구성됨
CPU와 메모리는 양방향으로 위 그림과 같이 주고 받는다. CPU는 주소를 가지고 메인 메모리에 요청을하거나 해당 주소에 계산 결과를 저장하고, 메모리는 요구하는 주소에 저장되어 있는 데이터를 CPU에게 전달
메인 메모리?
CPU가 직접 접근할 수 있는 메모리
프로그램이 실행될 때 프로그램이 복사되어 메인 메모리에 적재 → 프로세스가 됨
CPU는 PC가 지시하는 대로 연산을 수행한 후 메인 메모리에 데이터를 저장하거나 필요한 데이터를 요구
각 프로세스에는 별도의 메모리 공간이 존재
메모리는 일반적으로 상주 운영체제용 / 유저 프로세스용 으로 구분
일반적으로 여러 유저 프로세스가 메모리에 적재되어 있는것이 바람직 (멀티 프로그래밍(프로세싱)) → 메모리에 가져오기를 기다리고 있는 프로세스에 사용 가능한 메모리를 할당하는 방법 고려 필요
base register과 limit register을 이용
개별적인 메모리 공간을 분리하기 위해, 특정 프로세스만 접근할 수 있는 합법적인(legal) 메모리 주소 영역을 설정, 프로세스가 합법적인 영역만을 접근하도록 하는 기능이 필요
기본 레지스터(base register): 가장 작은 합법적인 물리 메모리 주소
상한 레지스터(limit register): 주어진 영역의 크기
메모리 공간의 보호
기준과 상한 레지스터 하드웨어를 통하여 유저 프로그램이 운영체제나 다른 유저의 코드나 데이터 구조를 수정하는 것을 방지
CPU에서 주소를 사용하는데 이 주소가 해당 프로그램의 base나 limit 범위를 벗어나면 인터럽트가 발생하여 그 프로그램을 강제로 종료
각 논리 주소는 상한 레지스터에 의해 지정된 범위 내에 존재해야 함

Address Binding

주소의 할당(Address Binding)
프로그램은 바이너리 실행가능한 파일로 디스크 안에 존재
프로그램이 실행되려면, 메모리로 적재한 뒤 프로세스 컨택스트 내에 배치해야 함(프로세스가 됨)
프로그램 실행 중 : 디스크 ~ 메모리 프로세스 이동
프로세스의 주소는 주소 0x0(0번지)에서 시작되지 않는다
원시 프로그램(소스 프로그램)에서의 주소는 일반적으로는 기호(symbolic)형태로 표현
컴파일러는 이런 기호 주소재배치 가능한 주소에 바인딩
Linker나 Loader는 재배치 가능한 주소절대 주소로 바인딩
유저 프로그램의 단계별 처리 과정 (프로그램 빌드 과정) - 참고, 그림은 중요
주소의 할당(Address Binding)의 구분
메모리 주소 공간에서 명령어와 데이터의 바인딩은 그 바인딩이 이루어지는 시점에 따라 구분
컴파일 시간 바인딩(compile time binding)
컴파일 시간에 프로세스가 메모리에 상주할 위치를 미리 알 수 있다면 컴파일러는 절대코드를 생성할 수 있음
적재 시간 바인딩(load time binding)
프로세스가 메모리에 상주할 컴파일 시간을 알 수 없는 경우, 컴파일러는 재배치 가능한 코드를 생성해야 함
실행 시간 바인딩(execution time binding)
프로세스가 실행 중에 한 메모리 세그먼트에서 다른 메모리 세그먼트로 이동할 수 있는 경우 바인딩은 실행 시간까지 연기되어야 함

논리 주소, 물리 주소, MMU

논리 대 물리 주소 공간
논리 주소 : CPU에서 생성한 주소(가상 주소)
물리 주소 : 메모리 장치가 보는 주소
메모리-주소 레지스터에 적재되는 주소
컴파일 시간 바인딩, 적재 시간 바인딩 기법은 논리주소 = 물리주소
논리주소와 물리주소는 실행 시간 바인딩이 다르다
논리 주소 공간 : 유저 프로그램에 의해서 생성된 논리 주소들의 집합
물리 주소 공간 : 논리 주소들에 대응되는 물리 주소들의 집합
논리 주소에서 물리 주소로의 실행 시간 맵핑은 MMU(메모리 관리 장치, Memory Management Unit)라고 하는 하드웨어 장치에 의해 수행
주소가 메모리로 전송될 때, 유저 프로세스에 의해 생성된 모든 주소에 재배치 레지스터(기본 레지스터)의 값이 추가됨
유저 프로그램은 실제 물리적 주소에 절대 접근할 수 없음
유저는 논리주소가 어디로 매핑될 지 정의 불가
MMU와 동적 재배치
MMU(Memory management unit)
논리 주소를 물리 주소로 매핑해주는 하드웨어 장치
재배치 레지스터를 이용한 동적 재배치 (논리주소 → 물리주소)
MMU는 동적으로 논리 주소에 재배치 레지스터 값을 더하여 주소 변환(address translation 동작을 수행)
프로그램이 메모리에 할당될 때마다 다른 주소공간을 사용
MMU를 통해 메인 메모리에 해당 주소를 사용할 수 있는지 여부를 생각하지 않고 주소를 사용
MMU 구성
Dynamic Loading
전체 프로그램과 데이터를 물리적 메모리에 적재하는 것이 필요한가?
프로그램의 크기가 메모리보다 클 경우, 혹은 프로그램이 너무 클 경우 불필요
Dynamic Loading
메모리 공간 활용성이 좋아진다
호출 전까지 적재되지 않음
필요할 때만 적재됨
재배치 링킹 로더(relocatable linking loader)가 필요한 루틴을 적재하기 위해 호출됨
프로그램의 주소 테이블에 해당 변화를 반영해 업데이트
Dynamic Linking
DLLs : Dynamically Linked Libraries
프로그램이 돌아갈 때, 다수의 유저 프로그램들에 링크되는 시스템 라이브러리들
shared libraries 라고 불리기도 함
.so(linux), .dll(window)
자주 사용되는 표준적인 함수를 매번 직접 작성해서 사용하는 것은 지나치게 시간 소모적이므로 표준화할 수 있는 함수를 미리 만들어서 모아 놓은 것.
ex) fork(), exec()
Static linking
실행 파일 이미지(.exe)을 만들 때 라이브러리와 프로그램 코드를 링커에 의해 같이 포함시켜 프로그램 파일 이미지를 만드는 것
Dynamic linking
링킹을 실행 시간(execution time)까지 연기하는 것

연속 메모리 할당과 단편화

연속 메모리 할당과 단편화 개념을 이해
부팅 직후에 메모리 상태를 살펴보면, 운영체제만 할당되어 있고 비어있는 상태
비어있는 공간을 hole 이라 부른다.
부팅 직후에는 운영체제와 big single hole이 있는 상태이다.
시간이 지나면서 프로세스가 생성되고 종료하고를 반복하면, 여러 곳에 서로 다른 크기의 홀(hole)이 존재할 것이다. 이러한 상태를 scattered holes 라고 한다.
메모리는 운영체제와 여러개의 유저 프로세스들로 나눠진다
멀티 프로그래밍 : 해당 유저 메모리 공간에 프로세스가 여러개 올라감
유니 프로그래밍 : 해당 유저 메모리 공간에 프로세스가 하나만 올라감
메모리 할당 방식들
연속적 할당
Fixed size allocation : Fixed partition
variable size allocation : Variable parition
파티션 기반 할당
variable size allocation : Segmentation
Fixed size allocation : Paging

연속 메모리 할당 방식

메모리 할당 – 다중 파티션 방식(고정 분할, Fixed partition)
다중 파티션 방식
메모리를 고정된 크기의 여러 파티션으로 나눔
각 파티션은 정확히 하나의 프로세스를 포함할 수 있음
멀티 프로그래밍의 정도는 파티션 수에 의해 결정됨
파티션이 비어 있으면 입력 큐에서 프로세스가 선택되어 비어있는 파티션에 로드됨
프로세스가 종료되면 파티션을 다른 프로세스에서 사용할 수 있게 됨
메모리 할당 – 가변 분할(동적 분할, Variable partition)
가변 분할 기법에서, OS는 사용 가능한 메모리 부분과 사용 중인 메모리 부분을 나타내는 테이블을 유지
모든 메모리는 유저 프로세스에 사용 가능. 사용 가능한 메모리의 큰 블록을 hole이라고 지칭
동적 할당 종류. (가변 분할 종류 , Variable partition 종류) 문제 : Free hole들의 리스트로부터 크기가 n인 요청을 어떻게 만족시켜 줄 것인가?
→ 시간, 메모리 이용 효율 고려 필요 (3가지 전략 존재)
최초 적합(First fit)
첫 번째 사용 가능한 가용 공간 선택
할당할 프로세스 크기보다 크거나 같은 hole을 탐색하는 순서 중에서 가장 먼저 찾은 hole에 프로세스를 할당하는 것이다.
집합의 시작에서부터 검색하거나, 지난번 검색이 끝났던 곳에서 시작
최적 적합(Best fit)
사용 가능한 공간들 중에서 차이가 가장 작은 공간 선택
할당할 프로세스 크기와 hole 크기의 차이가 가장 작은 hole에 프로세스를 할당
hole 크기는 프로세스 크기보다 반드시 커야 한다.
아주 작은 가용 공간을 만들어 냄
리스트가 크기 순으로 되어 있지 않다면 전체 리스트를 검색해야 함
최악 적합(worst fit)
가장 큰 가용 공간 선택
할당할 프로세스 크기와 hole 크기의 차이가 가장 큰 hole에 프로세스를 할당하는 것
할당 이후 남는 자유공간이 충분히 커서 다른 프로세스들이 사용해야 함
자유공간이 크기 순으로 정렬되어 있지 않으면 전 리스트 다 검색해야 함
문제
first fit
best fit
worst fit

단편화

단편화(Fragmentation) 개념
외부 단편화
요청을 충족하기에 충분한 총 메모리 공간이 있지만, 사용 가능한 공간이 연속적이지 않아 할당이 안 되는 경우
스토리지가 여러 개의 hole들로 분할됨
총 메모리 저장 용량과 평균 프로세스 크기에 따라 외부 단편화는 사소하거나 중요한 문제일 수 있음
일반적인 해소 방법
물리 메모리를 고정 크기 블록으로 나누고 블록 크기에 따른 정수배로 메모리 할당
연속적 할당의 경우 외부 단편화 발생
최초 적합, 최적 적합 모두 외부 단편화가 발생함
내부 단편화
프로세스에 할당된 메모리가 요청된 메모리보다 약간 클 수 있음. 프레임과 할당 메모리 사이의 사이즈 차이로 인해 남는 부분
페이징 방식의 경우 내부 단편화 문제 발생
단편화 해결 방식 - 압축
외부 단편화 문제에 대한 하나의 솔루션 (디스크 정리-조각모음)
사용 가능한 모든 메모리를 하나의 큰 블록으로 만들도록 메모리를 모으는 것
재배치가 동적이고 실행시간에 수행되는 경우만 가능
압축이 가능할 경우 비용 결정이 필요
모든 프로세스를 메모리의 한쪽 끝으로 이동
단점 : hole을 옮기는 오버헤드가 너무 크고, hole과 process 두개를 하기 때문에 어떻게 옮겨야 빠르게 합칠 수 있는지에 대한 최적 알고리즘이 존재하지 않는 큰 단점이 존재

페이징(paging)

페이징의 개념과 구성 이해
Compaction을 사용하면 외부 단편화는 해결할 수 있지만, 그로 인해 발생하는 오버헤드와 비효율적인 성능으로 사용하기는 어렵다. 페이징은 hole을 가지고 해결하려 한 것이 아니라 프로세스를 작은 크기로 나눠서 외부 단편화를 해결하려고 하였다.

페이징 개념

내부 단편화에서는 발생X
프로세스의 물리 주소 공간이 연속적이지 않도록 하는 메모리 관리 체계
외부 단편화 방지, 메모리 압축 필요 상황 방지
기본 방법
물리 메모리를 프레임(frame)이라고 하는 고정된 크기의 블록으로 나눔
논리 메모리(프로세스)를 페이지(page)라고 하는 동일한 크기의 블록으로 나눔
주소 변환(Address Translation)
CPU에 의해 생성된 모든 논리 주소는 페이지 번호(p), 페이지 오프셋(d) 두 부분으로 나뉨 (몫과 나머지)
페이지 테이블(Page Table)
물리 메모리에 있는 각 프레임의 기본주소를 포함. 프레임의 기본 주소가 페이지 오프셋과 결합되어 물리 메모리 주소 정의
여러 개의 재배치 레지스터 ⇒ 각 페이지의 실제 주소로 변경
즉, 프로세스(논리 메모리)는 메모리(물리 메모리)로 가기 전에 각 페이지의 실제 메모리 주소가 저장되어 있는 테이블에서 물리 주소로 변경
페이지 번호(p) : 페이지 테이블에 대한 인덱스로 사용
오프셋(d) : 변하지 않는 값. d는 페이지 크기에 따라 달라진다.
페이지 크기(Page Size)
페이지 크기는 일반적으로 2의 거듭제곱. 페이지당 4KB ~ 1GB
외부 단편화 방지
논리 주소 공간 사이즈가 2m2^m, 페이지 사이즈가 2n2^n 바이트라고 할 때, 논리 주소의 상위 m-n 비트페이지 번호를 지정, 하위 n비트페이지 오프셋 지정
p는 페이지 테이블의 인덱스, d는 페이지 내의 오프셋
페이징 하드웨어 (페이징 동작 방식)
페이징 하드웨어
1.
전체 구성
a.
페이지 번호-페이지 테이블-물리 메모리 주소
2.
offset(d)은 그대로 가져감
3.
page(p) 변수를 frame 변수(f)로 바꿔주는 page table을 통과하여 나온 값을 가지고 물리 주소를 찾으면 된다.
4.
물리 메모리에 가서 몇 번 프레임에 가서 오프셋 d만큼 이동한 후 해당 주소값 알려달라고 말함 → 해당 위치에 메모리 적재
논리 및 물리 메모리로 이루어진 페이징 모델
페이지 테이블 ⇒ 물리메모리 매핑
바이트 페이지를 가진 32바이트 메모리 페이징 예
논리 주소에서, n=2, m=4일때, 논리주소 0, 3, 4, 13은 어디에 위치하게 될까?
페이지 번호(p), 페이지 오프셋(d) 두 부분으로 나뉨 (몫과 나머지)
논리 주소공간 크기 = 242^4 = 16
page size = 222^2 = 4
page number bit : 4-2 = 2
off set bit : 2
논리 주소 0 → page 0, offset 0. 물리주소 20[=(5x4)+0]
논리 주소 3 → page 0, offset 3. 물리주소 23[=(5x4)+3]
논리 주소 4 → page 1, offset 0. 물리주소 24[=(6x4)+0]
논리 주소 13 → page 4, offset 1. 물리주소 9[=(2x4)+1]

페이징 시 내부단편화

페이징으로부터 연속 메모리 할당을 하면서 외부 단편화가 발생하는 문제는 해결
외부 단편화는 없으나, 내부 단편화 존재
프로세스 크기가 페이지 크기의 배수가 아닐 경우, 마지막 페이지는 한 프레임을 다 채울 수 없다 마지막 페이지 프레임은 전부 할당되지 않음. ⇒ 내부 단편화
내부단편화는 해결할 방법이 없다. 하지만 내부단편화는 외부단편화에 비해 낭비되는 메모리 공간은 매우 적다. 내부단편화의 최대 낭비되는 크기는 page size - 1 이 된다.(외부 단편화는 최대 전체 메모리의 1/3이 낭비된다고 이전에 살펴봤다.) 이는 무시할 정도로 작은 크기이다.
평균적으로는 프로세스 당 반 페이지 정도의 내부 단편화를 예상 (참고) → 페이지 크기가 작을수록 좋은가? ⇒ 매핑 수 증가 → 페이지 크기가 클수록 페이지 테이블의 크기가 반비례 관계로 커지게 됨 → 디스크 입장에서는? 페이지 크기가 클수록 효율적(OS 입장)

TLB (Translation Look-aside Buffer)

메인 메모리에 존재하는 페이지 테이블
PTBR (page table base register)
페이지 테이블을 가르킴
페이지 테이블이 메인 메모리에 존재한다
보다 빠른 컨텍스트 스위치, 하지만 메모리 접근 시간이 아직 느림
2번의 메모리 접근이 필요
페이지 테이블 엔트리 접근
실제 데이터 접근
PTLR(Page table length register)
페이지 테이블의 사이즈를 가르킴
하드웨어 지원 - TLB
페이지 테이블은 고속 논리 회로로 설계되어 페이지 주소 변환을 매우 효율적으로 만듬
페이지 테이블을 cpu 내부 저장 케이스, 메인 메모리에 저장
1.
페이지 테이블을 CPU 내부에 저장할 경우, 여러 개의 레지스터로 페이지 테이블을 만듦 레지스터 사용은 페이지 테이블이 작을 경우 적합
2.
대부분의 컴퓨터는 페이지 테이블을 메인 메모리에 저장. 페이지 테이블 기준 레지스터(PTBR, Page-Table Base Register)로 하여금 한번 더 페이지 테이블을 가리킴 → 메모리 접근 시간 문제 발생
a.
주소 i에 접근 → i를 찾기 위해서 페이지 테이블 접근(논리 → 물리 주소)
b.
페이지 테이블 내 메모리 자체를 위해서 또 한번 접근 → 메모리 접근 2배
다른 페이지 테이블 사용하려면 PTBR만 조금 바꿔서 다른 페이지 테이블 지정 가능 → Context switch 덜해서 시간 절감된다
TLB(Translation Look-aside Buffers) 캐시 사용
페이지 테이블을 CPU에 만들 때나 메모리에 만들 때 둘 다 장단점이 확실하기 때문에, 이를 해결하기 위해 페이지 테이블도 하드웨어 캐시로 만들어 해결
아주 빠른 룩업 하드웨어 캐시 메모리 사용
TLB : 페이지 테이블을 별도의 칩(SRAM)으로 만들어서 CPU와 물리 메모리 사이에 위치시키는 것
Key(혹은 tag), Value로 구성
찾으려는 페이지를 동시에 내부 키랑 비교 → 같은 값 frame 번호를 알려줌
TLB는 페이지 테이블과 함께 사용됨. 페이지 테이블 항목 중 일부만 포함
페이지 번호를 찾으면 프레임 번호를 즉시 사용. 메모리 액세스에 사용
페이지 번호가 TLB에 없으면 페이지 테이블에 대한 메모리 참조를 새로 생성
똑같은 번호를 또 부르면 캐시의 특성 상, 다음부터는 더 빨라짐
TLB가 장착된 페이징 하드웨어 예시
TLB hit
TLB에 유효한 페이지 넘버가 있는 경우
TLB에 유효한 페이지가 있다면 TLB를 읽는 시간과 실제 메모리를 읽는 시간만 있으면 된다.
TLB miss
TLB에 유효한 페이지 넘버가 없는 경우
TLB에 유효한 페이지가 없다면 이를 다시 메모리에서 가져와야 하므로 메모리를 총 2번 읽어야 한다.
hit ratio
TLB에 유효한 페이지 번호가 얼마나 존재하는지 비율

페이징을 이용한 메모리 보호(Paging Protection)

페이징 - 메모리 보호(Protection)
페이징을 이용한 메모리 보호는 각 프레임과 관련된 보호 비트에 의해 수행됨
1.
페이지 읽기, 쓰기 또는 실행 전용 비트 (참고)
대표적으로 페이지 테이블마다 r(read), w(write), x(execute) 비트를 두어, 해당 비트가 켜져있을 때 그 수행이 가능하도록한다.
보호 비트를 검사하여 읽기 전용 페이지에 쓰기를 시도하면 위반을 검출함
OS가 hardware에 trap 발생
2.
유효-무효 비트 ⇒ 보호 비트 검사 (중요)
유효”로 설정되면 관련된 페이지가 프로세스의 합법적인 페이지임을 나타냄 → legal
무효”로 설정되면 그 페이지는 프로세스의 논리 주소 공간에 속하지 않는다는 것을 나타냄 → illegal
페이지 테이블에서의 유효(v) / 무효(i) 비트

공유(Sharing)

공유
메모리 낭비를 방지하기 위함이다. 같은 프로그램을 쓰는 복수 개의 프로세스가 있다면, 프로세스의 메모리는 code + data + stack 영역으로 나뉘는데 프로그램이 같다면 code 영역은 같을 것이다.
그러므로 하나의 code 영역을 복수 개의 프로세스가 공유하여 메모리 낭비를 줄이는 것이다.
단, code가 공유되려면 code가 변하지 않는 프로그램이어야 한다.
non-self-modifying code = reentrant code(재진입가능 코드) = pure code 라고 한다.
reentrant code
실행 중에 자기 자신을 바꿀 일이 없는 코드
ex)libc (standard C library)

공유 페이지(shared pages)

페이징의 장점 : 공통 코드(common code)를 공유할 수 있음
멀티 프로그래밍 환경에서는 동일한 코드가 reentrant code라면 굳이 같은 코드를 다른 물리 공간에 또 한번 할당할 필요 없음
⇒ 일치하는 부분(정보)를 동시에 같이 사용할 수 있도록 물리 메모리에서 여러 번 참조 가능

페이지 테이블 구조

페이지 테이블을 구성
큰 논리 주소 공간은 페이지 테이블을 너무 크게 만든다
3가지 대표적인 기술들로 페이지 테이블을 구성한다
Hierachical Paging (계층적 페이징)
Hashed Page Table (해싱 페이지 테이블)
Inverted Page Table (역 페이지 테이블)
Hierachical Paging (계층적 페이징)
논리 주소 공간을 여러 개의 테이블로 쪼갠다
Two level page table (forward mapped page table)
Hashed Page Table (해싱 페이지 테이블)
32 비트보다 큰 주소 공간을 다루기 위해서
hash 함수를 이용해 매핑된 hash 테이블의 값(가상의 페이지 넘버)을 가지고 논리 주소를 물리 주소로 변환
Inverted Page Table (역 페이지 테이블)
어떤 프로세스가 어떤 페이지를 가지고 있는지 역으로 저장 ⇒ 어떤 pid의 page number(p)를 이용해서 물리주소로 매핑
logical address : <Pid, p, d>
각 실제 페이지를 위한 하나의 엔트리
가상 주소를 구성
프로세스에 대한 정보

페이징의 장단점

장점
물리적 메모리 할당 용이
사용 가능한 프레임 목록에서 할당
외부 단편화 없음
프로그램 조각를 "page out"하기 쉽습니다.
모든 조각의 크기가 동일함(페이지 크기)
안전하지 않은 접근로부터 페이지 보호 용이
쉬운 페이지 공유
단점
외부 단편화는 없으나, 내부 단편화 존재
메모리 참조 오버헤드 발생
물리적 메모리 액세스를 위한 여러 번의 메모리 참조 → TLB를 통해 해결
페이지 테이블을 저장하는 데 필요한 메모리가 클 수 있음
Page the page tables, multi-level page tables, inverted page tables

Swapping

backing store(swap device)
swapping 과정으로 인한 프로세스 이미지를 저장하기 위해 하드디스크의 일부분을 분리하여 사용
Swapping이란?
메모리에 적재되어 있는 프로세스 중에서 오랫동안 사용하지 않은 프로세스를 프로세스 이미지 형태로 만든 후 하드디스크(Backing store)에 내려보낸다.
swap-out : 메모리에서 Backing store로 가는 것 (필요 없을 때)
swap-in : 다시 Backing store에서 메모리로 가는 것 (필요할 때만)
모든 프로세스들에게 전체 물리 주소 공간이 실제 시스템의 물리 메모리를 초과할 수 있게 해준다
시스템의 멀티 프로그래밍의 정도를 증가시킨다
기존의 Swapping
전체 프로세스들을 메인 메모리에서 backing store로 옮기는 것
전체 프로세스를 스와핑하는 것은 너무 비효율적
현재는 프로세스의 크기가 커지고, 하드디스크는 메인 메모리보다 속도면에서 매우 느리므로 swapping 동작의 오버헤드는 크다
페이지(page)를 이용한 swapping
전체 페이지 대신 페이지를 이용해 스와핑 시도
스와핑 비용 감소
page in, page out
Swap-out된 프로세스는 다시 swap-in을 할 때, 이전의 메모리 주소 공간이 아닌 새로운 주소 공간으로 갈 수도 있다. 이는 해당 프로세스가 backing store에 있는 동안 다른 프로세스가 해당 주소 공간을 사용할 수 있기 때문에다. 하지만 이는 MMU의 재배치 레지스터로 인해 어디에 적재되는지 상관없이 정상적으로 수행할 수 있다

세그멘테이션(Segmentation)

페이징은 프로세스를 물리적으로 일정한 크기로 나눠서 메모리에 할당
세그먼테이션은 프로세스를 논리적 내용을 기반으로 나눠서 메모리에 배치하는 것
논리적 내용은, 어떤 의미론적 단위를 의미
세그먼테이션은 프로세스를 세그먼트(segment)의 집합으로 생각한다. 앞에서도 말했듯, Process는 Code, Data, Stack 과 같은 구조로 나뉜다. 물론 code, data, stack 각각 내부에서 더 작은 세그먼트로 나눌 수도 있다.
segment가 가변 사이즈라서 외부 단편화 문제는 더 심각해진다.

Segment Table

page size가 동일하지 않기 때문에, frame 번호로 논리 주소와 물리 주소를 연결할 수 없다.
table이 bound를 가지고 있어야 한다.
세그먼트 번호와 시작 주소(base), 세그먼트 크기(limit)를 엔트리로 갖는다.
페이징과 마찬가지로 논리 주소의 규약을 가지며, 이번에는 p가 아니고 s로 표기한다.
세그먼트 테이블과 프로세스가 할당된 메모리의 모습이다.
페이징 주소변환과 동일하게 d는 논리주소와 물리주소가 동일하다.
물리주소 a는 base[s] + d  로 계산
논리주소 (2, 100)
2(4300) + 100 = 4400 < 4700(base+limit)
논리주소 (1, 500)
1(6300) + 500 = 6800 > 6700(base+limit)
⇒ 인터럽트로 인해 프로세스 강제 종료(범위를 벗어남)
세그먼테이션에서 보호와 공유
페이징보다 세그먼테이션에서의 보호와 공유는 더 효율적이다.
보호에서는 세그먼테이션 역시 r, w, x 비트를 테이블에 추가하는데, 세그먼테이션은 논리적으로 나누기 때문에 해당 비트를 설정하기 매우 간단하고 안전하다.
페이징은 code + data + stack 영역이 있을 때 이를 일정한 크기로 나누므로 두 가지 영역이 섞일 수가 있다. 그러면 비트를 설정하기가 매우 까다롭다.
공유에서도 마찬가지다. 페이징에서는 code 영역을 나눈다해도 다른 영역이 포함될 확률이 매우 높다.
세그먼테이션은 정확히 code 영역만 나누기 때문에 더 효율적으로 공유를 수행할 수 있다.

세그먼테이션과 페이징

세그먼테이션은 페이징과 유사하고 보호와 공유에서는 더 나은 성능을 보여주었지만, 현재 대부분은 페이징 기법을 사용한다. 그 이유는 세그먼테이션에는 치명적인 단점이 있기 때문이다.
외부 단편화
메모리 할당을 처음 시작할 때 다중 프로그래밍에서의 문제는 크기가 서로 다른 프로세스로 인해 여러 크기의 hole이 발생한다. 이로 인해 어느 hole에 프로세스를 할당하는 것에 대한 최적화 알고리즘이 존재하지 않고, 외부 단편화로 인해 메모리 낭비가 크다고 했었다.
세그먼테이션도 똑같은 문제점이 발생한다. 왜냐하면 세그먼테이션은 논리적인 단위로 나누기 때문에 세그먼트의 크기가 다양하다. ⇒ 다양한 크기의 hole이 발생하므로 외부 단편화의 문제가 발생한다.
Paged segmentation
결론적으로 세그먼테이션은 보호와 공유에서 효율적이고,
페이징은 외부 단편화 문제를 해결할 수 있다.
그러므로 두 가지를 합쳐서 사용하는 방법이 나왔다. 두 장점을 합치기 위해서는 세그먼트를 페이징 기법으로 나누는 것이다.(Paged segmentation)
하지만 이 역시 단점이 존재한다. 세그먼트와 페이지가 동시에 존재하기 때문에 주소 변환도 두 번해야한다. 즉 CPU에서 세그먼트 테이블에서 주소 변환을 하고, 그 다음 페이지 테이블에서 또 주소 변환을 해야한다.