본문 바로가기

운영체제

Chap 4.

메모리 가상화 (Memory Virtualization)

- OS는 physical memory를 가상화함

- OS는 가상 메모리 공간을 각 프로세스마다 제공함

=> 각 프로세스가 전체 메모리를 사용하는 것처럼 보임

 

메모리 가상화의 목표

Transparency (투명성)

  • 프로세스는 메모리가 공유되고 있다는 사실을 인식하지 못해야함
  • 프로그래밍을 위한 편리한 추상화 제공 (크고 연속적인 메모리 공간)

Efficiency (효율성)

  • 다양한 크기의 요청으로 인한 fragmentation(단편화)를 최소화함 (공간)
  • 하드웨어의 도움을 받음(시간) 역시 자본이 최고야

Protection (보호)

  • 다른 프로세스로부터 프로세스들과 OS를 보호
  • Isolation : 프로세스가 fail 하더라도 다른 프로세스들에 영향을 주지않음
  • Cooperating processes 끼리 서로 메모리 일부를 공유할수있음

OS in The Early System

- 메모리에 오직 하나의 프로세스만 로드할수있음.

- 낮은 활용도( utilization )와 효율성( efficiency )

Multiprogramming and Time Sharing

- 메모리에 여러 프로세스를 로드

=> 하나씩 짧게 실행, 프로세스를 스위칭하여 실행

=> 활용도( utilization )과 효율성( efficiency ) 증대

 

==> 단점 : 다른 프로세스의 잘못된 메모리 액세스 문제가 발생할수있음

메모리 공간 ( Address Space )

- OS는 물리적 메모리의 추상화를 생성

- 주소 공간에는 실행 중인 프로세스에 대한 모든 것이 포함되어있음

- (프로그램) 코드(code), 힙(heap), 스택(stack) 등으로 구성 (free는 안 쓰고 있는 공간)

 

코드( Code ) : instruction이 있는 곳

힙( Heap ) : 동적으로 할당된 메모리 영역

-> C언어에서는 malloc, 객체지향언어에서는 new

스택( Stack ) : 주소(return address)나 값(value)을 저장하는 영역

-> 지역 변수( local variables ), arguments to routines

 

이런식으로 물리 메모리와 주소공간을 연결한다.

가상 주소 ( Virtual Address )

- 모든 프로그램에서의 주소는 모두 가상 주소

=> OS는 가상주소를 물리주소로 바꿔준다

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
	printf("location of code : %p\n", (void *) main);
	printf("location of heap : %p\n", (void *) malloc(1));
	int x = 3;
	printf("location of stack : %p\n", (void *) &x);
	return x;
}

 

 

주소 변환 ( Address Translation )

효율적인 메모리 가상화 및 제어
- 메모리 가상화는 효율성 및 제어를 위해 limited direct execution(LDE) 과 유사한 전략을 사용

- 메모리 가상화에서 효율성과 제어는 하드웨어 서포트로 달성됨
EX) 레지스터, TLB( (Translation Look-aside Buffer ), 페이지 테이블

 

- 하드웨어는 가상 주소를 실제 주소로 변환
=> 원하는 정보는 실제로는 물리적 주소에 저장됨

- OS는 메모리의 어떤 위치가 비어 있고 어떤 위치가 사용 중인지 추적해야함

 

가정

- 사용자의 주소 공간-> 물리적 메모리에 연속적으로 배치되어야함
- 메모리 -> 주소 공간의 크기가 물리적 메모리 크기보다 작아야 함

- 각 주소 공간의 크기가 정확히 같아야함

 

이러한 C언어 코드가 있다고 한다면, (이 코드는 Load, Increment, Store를 하는 코드)

void func()
	int x;
	...
	x = x + 3; // this is the line of code we are interested in
128 : movl 0x0(%ebx), %eax ; load 0+ebx into eax
132 : addl $0x03, %eax ; add 3 to eax register
135 : movl %eax, 0x0(%ebx) ; store eax back to mem

어셈블리어 코드는 이러하다(Load, Add, Store)

=> OS는 프로세스를 물리적 메모리에 저장한다(주소 0이 아님), 하지만 주소공간(가상메모리)은 0에서부터 시작한다

 

Software-based relocation (정적)

- OS가 각 프로그램을 메모리에 로드하기 전에 다시 작성
- 정적( static ) 데이터 및 함수의 주소 변경

장점

- 하드웨어 서포트가 필요하지않음

 

단점

- 프로세스가 OS 또는 다른 프로세스의 메모리 영역을 파괴할 수 있음

- 모든 메모리의 주소를 읽을수있음(No privacy)

- 주소 공간을 배치한 후에는 변경할 수 없음

- external fragmentation(외부 단편화)로 인해 새 프로세스를 할당받지 못할 수 있음

 

Hardware-based relocation (동적)

- MMU( Memory Management Unit , 메모리 관리 유닛)는 모든 메모리 참조 명령어의 주소변환을 수행함

- 하드웨어에 의한 Protection

=> 만약 가상 주소가 유효하지 않으면 MMU는 예외( exception )를 발생시킴

- OS는 현재 프로세스의 유효한 주소 공간에 대한 정보를 MMU에 전달

 

프로그램이 실행될때, Os는 프로세스가 물리 메모리의 어디에 load될지 결정

아까와 같은 코드에서는 이렇게 변환된다

메모리 가상화에 있어서 OS 이슈

=> 3가지 시점이 중요

- 프로세스가 실행을 시작할때 : 주소 공간을 위한 물리 메모리에서의 공간 찾기

-> free list : 사용하지않는 물리적 메모리 범위의 리스트

- 프로세스가 종료될때 : 메모리 회수( Reclaiming the memory for use ) (= 다시 free list로)

- 프로세스가 컨텍스트 스위칭될 때 : Saving and storing the base-and-bounds pair => PCB( process control block )에

 

Segmentation

Base and Bound Approach의 비효율성

- 큰 덩어리의 free space

- free space는 물리 메모리 공간을 차지함

- 주소공간이 물리적 메모리에 들어가지 않아, 실행할 수 없을 수도 있음

 

=> 주소 공간을 logical segments로 나누기

- segments는 특정 길이의 주소 공간의 연속적인 부분
- 각 segment는 주소 공간의 논리적 엔티티 ( logical entity ) 에 해당됨
- 논리적으로 다른 segment : code, stack, heap


각 segment 는 독립적으로
- 물리적 메모리의 다른 부분에 배치될 수 있음
- 확장 또는 축소
- 각 segment 마다 base, bound가 존재

 

 

offset(주소공간, 가상 메모리 주소)과 base를 알면 물리 메모리 주소를 알수있음

=> 가상 메모리 주소 + base는 정확한 물리 메모리 주소가 아님

=> 가상 메모리 -> 물리 메모리 변환을 통해 프로그램이 필요로 하는 메모리 주소 : 34920

????????????뭔소리지...

 

- 만약 잘못된 주소 (7KB 같이) heap이 참조하는 값 범위 밖이면, OS는 segmentation fault를 일으킨다, 하드웨어는 이를 out of bounds 라고함

 

세그먼트 참조 ( Referring to Segment )

	// 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)

Stack segment 참조

- stack은 위로 올라감

- 하드웨어는 그 방향을 확인함

=> 1: 양의 방향, 0: 음의 방향

세그먼트는 주소 공간 간에서 공유가능
- Code sharing (요즘도 쓰임)
- Protection bits
=> 읽기 read , 쓰기 write , 실행 execute 권한을 나타내는 세그먼트당 몇 개의 비트가 더 필요

Fine-Grained and CoarseGrained

- Coarse-Grained (넓게) : 작은 숫자의 segmentation

=> code, heap, stack

- Fine-Grained segmentation (상세하게) : 보다 유연한 주소공간

=> 더 많은 segment 를 지원하기 위해 하드웨어에서의 segment table이 필요함

 

단편화 (  Fragmentation )

- 외부 단편화( External Fragmentation ): 물리적 메모리에 작은 구멍이 생겨서 새로운 세그먼트를 할당하기 어려움

=> 물리적 메모리에 연속적으로 할당할수있는 공간이 없음

 

- Compaction (압축) : 물리적 메모리에서 기존 세그먼트를 재정렬

=>
- 실행 중인 프로세스를 중지
- 데이터를 어딘가로 복사
- 세그먼트 레지스터 값을 변경

=> 뭔가 작업이 많다

Segmentation 의 장점

- 스택과 힙이 독립적으로 확장 가능
- 내부 단편화 없음
- 빠르고 간편하며 하드웨어에 적합함
- 간편한 세그먼트 공유

=> base/limit 쌍에 동일한 변환을 적용, 세그먼트 수준에서 코드/데이터 공유(예: 공유 라이브러리)
- 각 세그먼트의 동적 재배치 지원

 

Segmentation 의 단점

- 각 세그먼트는 연속적으로 할당되어야 함
- 외부 단편화
- 큰 세그먼트를 위한 물리적 메모리가 충분하지 않을 수 있음
- 하나의 논리적 세그먼트에 크지만 사용 빈도가 낮은 힙이 모두 있는 경우 전체 힙이 여전히 메모리에 상주해야 함

 

'운영체제' 카테고리의 다른 글

Chap 6.  (1) 2023.10.23
Chap 5.  (0) 2023.10.22
Chap 3.  (0) 2023.10.15
Chap 2. 프로세스  (0) 2023.10.11
Chap 1. OS 개요  (2) 2023.10.10