뜌릅

메모리 관리 (페이징과 세그멘테이션) - 운영체제 본문

운영체제

메모리 관리 (페이징과 세그멘테이션) - 운영체제

TwoCastle9 2024. 2. 12. 19:41
반응형

메모리는 전통적으로 한정적이었습니다. 운영체제는 이 메모리를 효율적으로 운용하기 위해서 적절한 관리방법이 필요했고, 크게 나누어보면 가상메모리와 물리 메모리 2가지로 나누어 볼 수 있습니다.

 

모든 프로그램이 실행될려면 메모리에 탑재가 되어야 합니다. 이는 CPU가 메모리와 레지스터에만 접근이 가능하기 때문입니다. CPU는 메메모리 주소를 기반으로 작동을 하며, 우리가 아는 HDD나 SDD는 Block Device로 Block단위로 디바이스를 통하여 IO가 발생합니다. 

(NAND 메모리(RAM)는 PAGE단위로 NOR 메모리(Register)는 바이트 단위로 IO가 가능합니다.)

 

하지만 실제 모든 프로세스가 메모리의 0번지에서 시작하지는 않습니다.(커널메모리나 기타 등등) 따라서 이를 위해서 가상메모리가 도입되었습니다. 가상 메모리의 주소가 피지컬 메모리의 어디에 있는지를 정확히 아는 것이 또 이 간극간에 벌어지는 손실을 최소화 하는것이 메모리 관리의 핵심입니다. 또한 이 가상메모리는 멀티 프로그래밍 환경에서 다수의 프로세스를 수행하기 위해 메모리를 동적으로 분할하는 관리작업에 필수적입니다.

 

 

 

메모리 주소가 결정되는 시점 3가지

메모리에 맵핑시켜주는 시기별로 3가지로 나눕니다.

 

1. Compile time binding

컴파일까지 완료된 시점에서 메모리 주소가 결정되는 것을 의미합니다. 메모리의 시작 위치는 고정되어 있고, 이에 따라 모든 변수의 메모리를 Offset을 더하는 식으로 Stack이나 Heap을 생성합니다. 

당연히 고정되어 있으니 멀티 프로그래밍은 불가능하며 프로세스 또한 한개를 가정하였으므로 메모리 관리에 특별히 할 것이 없습니다. 

또 설정된 시작주소가 컴파일 할때마다 다를것이므로 컴파일된 파일은 다른환경에서는 작동하지 못합니다. 

 

2. Load time binding 

Load가 끝나고 메모리를 결정하는 방식에서 모든 컴파일러가 만드는주소들은 relocatable code(다시 재위치 시킬수 있다는 의미)입니다. 컴파일러를 다시 할 필요는 없습니다.

문제는 로드되고나면 메모리가 코드에 고정되게 됩니다. 이는  메모리상에서 위치이동이 안되는 결과를 초래합니다.  이 역시 멀티프로그래밍 환경에서는 안사용합니다.

 

 

Execution time binding.  (이때만 가상주소가 생겨남)

실행시 메모리 주소가 결정되는 방식입니다.

 

0을 시작 주소로 결정합니다. 하지만 이는 가상메모리에서의 0입니다. 실제 실행시 OS는 개입하여 CPU에게 물리 메로지 수소를 알려주고 Binding을 시킵니다. CPU가 발생하는 주소는 가상메모리 주소로 가짜주소입니다. 이러한 Mapping때문에 운영체제는 프로세스가 실행될때마다 추가적인 overhead가 발생하게 되므로 빠르게 맵핑시키는 방식이 필요했습니다. (이를 address translaton이라고함. )

그 방법은 주소변환을 하드웨어로 구워버리는 것입니다. 특별한 알고리즘이 아닌 말 그대로 회로로 구워버린 것입니다.   그러한 주소변환시켜주는 모듈을 mmu라고 합니다.  

 

변환시키는 방법

1. 테이블을 봐서 적절한 위치를 찾는다. 

 

2. MMU을 이용하여 Offset을 더하는 식으로 물리 메모리 위치로 손쉽게 맵핑한다.

 

일반적으로 모든 메모리 관리기법은 Execution time binding 일때를 기준으로 설명합니다.

암튼 본론으로 돌아와서 메모리 관리 기법에 대해 알아봅시다.

연속 할당

메모리에 프로세스를 그상태 그대로 탑재가 일어납니다.

 

이때 연속으로 할당할때 2가지 방식이 존재합니다. 프로세스 크기씩 분할하는 것과 고정된 사이즈들로 분할하는 것 2가지로 나눕니다. 

 

1. 고정 분할

고정된 사이즈로 분할하여 프로세스를 탑제하게 됩니다. 고정된 파티션들로 탑제가 되므로 구현이 간편하고 관리도 좋아지지만 내부 단편화 문제가 발생합니다. 예를들어 프로세스의 크기는 31메가이고 파티션의 고정된 크기가 30메가이면 해당 프로세스는 2개의 파티션을 사용하게 됩니다. 이때 1개의 파티션은 고작 1메가의 크기를 위해 30메가의 한정된 메모리 자원을 사용해야 하는 단점이 존재합니다. 

2. 동적 분할

동적분할은 프로세스의 크기만큼 분할하는 것입니다. 문제는 프로세스가 끝나고 Hole, 즉 동적 크기만큼의 빈공간이 생겼을 때입니다. 이때 다음 프로세스가 크기가 더 커서 탑제되지 못하거나 더 작아서 공간이 애매하게 남게 되는 일이 발생합니다. 

이를 외부 단편화라고 합니다. 

이러한 단편화를 줄이기 위한 여러 알고리즘이 있으나 이는 운영체제의 성능을 낮추므로 좋은 방식은 아닙니다.

 

외부단편화는 디스크에서 자주 볼수 있는데, 디스크 조각모음등이 외부단편화를 없애는 방법입니다.

 

연속 할당은 위와 같은 단점으로 메모리 관리 방법으로 잘 사용하지 않습니다.

 

페이징(Paging)과 세그멘테이션(Segmentation)이란

불연속 할당을 들어가기 앞ㅇ서 페이징과 세그멘테이션에 대해 간단하게 알아봅시다.

1. Paging은 가상 메모리의 IO단위인 Page에서 비롯되었습니다.(물리메로이의 단위는 Frame이라고 합니다.)

( PAGE는 주로 4MB(8MB,16MB....)단위로 구성되어 있습니다. )

Paging은 가상 메모리에서 읽고쓰는 작업 전반적인 것을 Paging이라고 통칭합니다. 

 

2. Segmentation은 메모리 관리 기법에서 사용하는 용어로 세분화입니다. 말 그대로 세분화로 기법에 따라서 여러 방법으로 메모리를 세분화 시키는 것을 Segmentation이라고 합니다.

 

 메모리가 디스크에서 읽고쓰고 또 CPU가 캐쉬나 레지스터로 읽고 쓰는 즉 SWAPING과 Backing Store 동작을 할때  적절한 페이징, 세그멘테이션 기법이 필요합니다.

불연속 할당

 

페이징 기법

프로세스들을 페이지들로 나누어서 가상메모리에 할당합니다. 즉 N개의 페이지가 존재한다면 실제 메모리는 이에 대응하는 N개의 프레임이 실행될 것입니다.(물론 모든 N개의 프레임이 물리 메모리에 올라올 필요는 없음.) 이를 이용하여 외부 단편화를 완전히 없앴습니다.

 

이러한 프로세스는 가상메모리에 저장되며 Page Table을 보고 실제 메모리 주소를 찾아갑니다. 

실제 메모리 주소는 빠른 접근을 위해 일부를 Caching시켜서 캐쉬메모리에 저장합니다. 그냥 메모리에 저장하면 2번의 메모리 접근이 발생하므로 느려집니다.

 

아무튼 이런 방식을 통해서 프로세스는 가상메모리에서는 연속적이나 물리메모리에서는 비연속적인 특징을 유지할수있습니다.

 

(대신 메모리 접근 성능이 약간 하락하긴함.... 그치만 메모리를 여러 프로세스가 공유할수 있으므로 외부 단편화와 멀티 프로그래밍의 장점이 존재 -> 이를 통해 C에서 배열 메모리가 연속적이라는 것은 실행 시점에서 메모리가 결정되고 가상메모리상에서 연속적이며 실제 메모리에서는 비연속적일수 있다는걸 알수있음. 또 같은 페이지를 2개의 프로세스가 공유 가능. 가상메모리상에서만 분리하고 물리메모리는 같은 하나를 사용하면 됨. 물론 이는 Illegal Access로 문제 생길수도 있으므로 접근제한을 해야할수도있음.)

 

세그멘테이션 기법

위의 기법은 얼핏 보아선 완벽해 보이나 문제가 발생합니다. 바로 Internal Fragment와 많은 Memory Access와 Disk Access가 발생할수 있다는 것입니다. 이 3가지 단점은 하나를 보완할려고 하면 나머지 2개는 커지는 식으로 작동합니다. Internal Fragment을 줄이기 위해 Page의 사이즈를 줄이게 되면 페이지의 개수가 늘어나 Memory Access와 Disk Access는 늘어나게 됩니다. 그 외에도 Process Table의 크기(이를 통해 물리 메모리 여유 공간도 줄어듦)와 TLB(프로세스 테이블을 캐쉬에 올린것)의 크기도 덩달아 늘어나 하드웨어 가격은 늘어나게 될것입니다. 

 

(테이블의 크기를 어떻게든 해결하기 위해 Hash Table, B+ Tree, Inversed 등 여러 방법이 있으나 이것은 다른이야기로 생각합시다.)

물론 좋은 알고리즘을 통해 Locality을 보완하여 Access자체를 줄일수도 있겠지만, 이것 또한 다른 이야기로 보도록 하고 이를 보완하기 위한 방법이 세그멘테이션 기법입니다.

 

 

페이징의 경우 Address space 한덩어리씩 잘라서 덩어리의 의미가 사라지는 단점이 있습니다. 집합이 프로그램이고 자기만의 특성을 가져야 하는데. 의미덩어리의 context paging으로 잘라서 흩어지는 바람에 의미가 유지가안되게 됩니다.

 

어떤 덩어리는 sharing 되고 어떤 덩어리는 read only이고 어떤 것은 write가능하고 이런식으로 의미단위가 있으면 좋습니다/

 

의미를 갖게 하기 위해 또 위의 단점을 해결하기 위해 segmentiaion이라는 방법이 나왔습니다. 하나의 segement 메모리에 연속적으로 올라가게 합니다.

 

이러한 세그멘트는 좋으나 여전히 외부 단편화의 문제점이 존재합니다.

반응형

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

파일 시스템 - 운영체제  (0) 2024.02.26
CPU 스케줄링 - 운영체제  (1) 2024.02.05