나의 브을로오그으

#22. 가상 메모리(Virtual Memory) 본문

Computer Science/운영체제

#22. 가상 메모리(Virtual Memory)

__jhp_+ 2022. 9. 9. 10:26

- 외부 단편화 (External Fragmentation)

  * 세그먼트 크기는 고정이 아니라 가변적

  * 크기가 다른 각 세그멘트를 메모리에 두려면 = 동적 메모리 할당

  * First-, Best-, Worst-fit, compaction 등 문제

- 세그멘테이션 + 페이징

  * 세그멘테이션은 보호와 공유면에서 효과적

  * 페이징은 외부 단편화 문제를 해결

  * 따라서 세그멘트를 페이징하자! - Paged Segmentation

(페이징은 보호와 공유 측면에서 문제가 있고, 세그멘트는 외부 단편화 문제가 있다

그래서 각 문제를 보완 할 수 있도록 두개를 조합하여 사용한다.)

예) Intel 80x86

방법) 프로세스를 세그멘트 단위로 자른 후에 각 세그멘트를 페이지 단위로 자른다.

좋은 방법일까??? 단점도 있다.

프로세스 -> 세그멘트 -> 페이지로 나누다 보니 보호와 공유, 외부 단편화 문제는 해결되지만 주소 변환의 부담이 높아진다.(trade off)

 

 

가상메모리

- 물리 메모리 크기 한계 극복

  * 물리 메모리보다 큰 프로세스를 실행?

  * e.g 100MB 메인 메모리에서 200MB 크기의 프로세스 실행

 

- 어떻게?

  * 프로세스 이미지를 모두 메모리에 올릴 필요는 없다.

  * 현재 실행에 필요한 부분만 메모리에 올린다!

  * 오류 처리 제외, 배열 일부 제외, 워드프로세스에서 정렬, 표 기능 제외 -> 동적 적재 (dynamic loading)과 비슷한 개념

 

 

요구 페이징

- Demand Paging

  * 프로세스 이미지는 backing store에 저장

  * 프로세스는 페이지의 집합

  * 지금 필요한 페이지만 메모리에 올린다.(load) -> 요구되는(demand) 페이지만 메모리에 올린다.

  

- 하드웨어 지원

  * valid비트 추가된 페이지 테이블

(실제 요구되는 페이지가 아닌경우에는 메모리 프레임에도 없다. 따라서 이부분을 페이지 테이블에 표현해야 하는데 -1로 표현할까? 그것도 하나의 방법이 될 수 있다. 그러나 더 좋은 방법은 각 페이지마다 valid 비트를 두어서 메모리 프레임에 없는 페이지를 표현한다.)

ex) 예를 들어

<페이지 테이블>

Page Index Page Number valid
0 a 1
1 b 1
2 invalidate 0
3 c 1
4 invalidate 0

(a, b, c는 각 메모리 프레임에 페이지가 올라와있는 프레임 넘버를 의미함)

만약 CPU가 2번째에 해당하는 페이지를 읽으려고 한다.

그런데 지금 해당 페이지는 메모리 프레임에 올려져 있지 않다. (invalidate)

이런 경우 CPU에 인터럽트 신호를 보낸다. OS에서 해당 인터럽트 처리를 하는 루틴을 실행한다.

그리고나서 하드디스크에서 메모리 프레임에 로드되어 있지 않은 페이지(예제 에서는 2번째 페이지)를 가져오는 루틴이 OS내부에 있는데 이를 실행한다.

 

<페이지 테이블>

Page Index Page Number valid
0 a 1
1 b 1
2 d 1
3 c 1
4 invalidate 0

그래서 2번째 페이지를 메모리 프레임에 올리고 페이지 테이블 역시 갱신된다.

이러면 이제 CPU가 정상적으로 해당 페이지를 처리하게 될 것이다.

이런식으로 CPU가 해당 페이지를 요구 페이지(demand page)라고 하고,

이를 요구 페이징(demand paging)이라고 한다.

가상 메모리(virtual memory)는 요구 페이징을 통해 만든다.

 

* backing store (=swap device)

(Demand Paging을 할 때 어떤 페이지에 fault가 있다는 말인 즉슨 invalidate상태라는것. 해당 페이지가 메모리 프레임에 로드되어 있지 않다. 페이지가 부재중이다.)

 

Page fault

- 페이지 결함 (= 페이지 부재)

  * 접근하려는 페이지가 메모리에 없다. (invalid)

  * Backing store에서 해당 페이지를 가져온다.

  * Steps in handling a page fault

- 용어: pure demand paiging vs prepaging

pure demand하다는 것은 진짜로 필요한 페이지만 페이징한다는 의미이다. 프로그램 처음 시작 시 어떤 페이지가 필요할까? 모른다. 당연히, 예를 들어 아래한글 같은 프로그램 실행 시 어떠한 페이지도 메모리에 올리지 않고 프로그램을 메모리에 로드한다. 즉, 지금 당장 필요하지 않은 페이지는 일체 올리지 않고 정말 프로그램 시작할 때 꼭 필요한 페이지만 올린다고 해서 pure demand paging이라고 표현한다.

그런데 프로그램 처음 실행되면 페이지가 필요할 텐데 pure demand paging했기 때문에 (당장 프로그램 실행할 때 필요한거 빼고 아무것도 페이지 로드 않함.) page fault가 일어나서 초반에는 paging하느라 느릴것이다. 그런데 이건 단점이고, 이렇게 함으로써 장점은 메모리 절약이 비약적으로 되고, 프로세스의 크기가 실제 메모리보다 크더라도 이부분을 다소 해결 할 수 있다.

이것과 반대되는 개념은 prepaging이라는 개념이다. 추후에 프로세스가 동작하는데 필요한 페이지다 싶으니 미리 메모리에 올려놓는 것이다. 메모리는 조금 낭비되더라도 (사용 안될수도 있으니) 미리 페이지를 load했기 때문에 page fault가 적게 일어나니 속도는 빠를것이다.

pure demand paging은 프로세스 동작 시 정말 필요한 것만 메모리에 로드한다면, prepaging은 추후에 필요할 것같은 페이지까지 같이 메모리에 로드한다.

 

- 비교: swapping vs demand paging

swapping은 말그대로 메모리에 로드되어있는 모든 페이지를 몰아낸다(clear)고 해서 프로세스를 메모리에서 해제하고, 프로세스 상태를 이미지 형태로 backing store에 저장, 그리고 해당 프로세스를 다시 실행 할 때 backing store에 저장된 프로세스 이미지를 메모리에 로드한다.

demand paging은 backing store에 저장되어 있는 page를 메모리에 로드하는 건데(위에서 자세히 설명함)

swapping은 메모리->backing store, backing store->메모리로 로드하거나 해제하는 단위가 프로세스 단위라면 demand paging은 page 단위이다.