프로그램 실행 시 프로그램의 전부를 물리 메모리에 적재하는 방법은 메모리를 효율적으로 사용하는 방법이 될 수 없다.
-> 초기에는 프로그램 전체가 메모리에 있을 필요가 없기 때문이다.
메모리를 효율적으로 사용하는 방법으로 필요한 페이지만 적재하는 방법이 있다. -> 요구 페이징이라고 한다.
요구 페이징은 가상 메모리 시스템을 사용하여 필요한 프로그램의 일부만 적재함으로써 메모리를 더 효율적으로 사용할 수 있도록 한다.
[요구 페이징]
1 ) 요구 페이징은 주소 공간을 페이지 단위로 나눈 뒤 필요할 때 메모리로 가져온다.
-> 페이지가 필요할 때만 메모리로 가져오는 것을 Lazy swapper라고 한다. (pager가 담당)
2 ) 페이지가필요하면 페이지 테이블을 참조
-> Valid-Invalid Bit 필요하다.
v라면 메인 메모리에 적재되어 있다는 의미이며
i라면 2가지 경우를 확인해야 한다.
1) 주소가 틀린 경우 : 프로그램을 종료함
2) 정당한 주소 : 페이지 폴트 발생 (페이지 메모리로 가져와야함)
3 ) 장점
- I/O시간이 줄어든다
- 메모리가 덜 필요하다
- 빠른 응답 속도
4 ) 하드웨어 지원이 필요
- valid-invalid를 가지고 있는 테이블
- 보조메모리장치(swap 공간을 위해서)
5 ) Pure demand paging
-> OS가 처임 시작되면 처음부터 page fault가 발생하면서 순차적으로 메모리에 올라옴
[페이지 폴트]
페이지를 참조 했지만 메모리에 없으면 page fault이며, 이 때 제어권이 운영체제로 넘어가서 주소를 확인하게 된다.
페이지 테이블에서 주소를 확인했는데 찾은 주소가 없다면 프로그램을 중지하고, 메모리에 있으면 페이지를 읽어온다.
[페이지 폴트가 일어나는 과정]
1 ) 운영체제에 트랩을 요청한다.
2 ) 레지스터들과 프로세스 상태를 저장한다.
3 ) 인터럽트 원인이 페이지 폴트임을 알아낸다
4 ) 페이지 참조가 유효한 것인지 확인하고, 보조저장장치에 있는 페이지의 위치를 알아낸다.
5 ) 저장장치에 가용 프레임으로의 읽기 요구를 낸다.
- 읽기 차례가 돌아오기까지 대기 큐에서 기다린다
- 디스크에서 찾는 시간과, 회전 지연 시간 동안 기다린다.
- 가용 프레임으로 페이지 전송을 시작한다.
6 ) 기다리는 동안에 CPU 코어는 다른 사용자에게 할당된다.
7 ) 저장장치가 다 읽었다고 인터럽트를 건다(I/O 완료)
8 ) 다른 프로세스의 레지스터들과 프로세스 상태를 저장한다.
9 ) 인터럽트가 보조저장장치로부터 왔다는 것을 알아낸다.
10 ) 새 페이지가 메모리로 올라왔다는 것을 페이지 테이블과 다른 테이블들에 기록한다.
11 ) CPU 코어가 자기 차례로 오기까지 다시 기다린다.
12 ) CPU 차례가 오면 위에서 저장시켜 두었던 레지스터들, 프로세스 상태, 새로운 페이지 테이블을 복원시키고 인터럽트 되었던 명령어를 다시 실행한다.
<주요 과정>
- 인터럽트의 처리
- 페이지 읽기
- 프로세스 재시작
[요구 페이지 예]
메모리 접근시간보다 page fault에서 swap하는 시간이 많이 걸리기 때문에 page fault를 줄여야한다.
Memory access time = 200nanos
Average page-fault service time = 8ms
EAT = (1-p) x memory_access + p(page fault overhead + swap out + swap in)
= (1 - p) 200 + p(8)
= 200 + p x 7,999,800
[요구 페이징 최적화]
1 ) 모든 프로세스를 swap 공간으로 카피
-> 파일 시스템에서 I/O를 하는 것보다 Swap 공간에서 I/O를 하는 것이 빠름.
2 ) 코드 부분은 그냥 버림으로써 swap-out 시간을 줄임.
3 ) Copy-on-Write
-> fork()를 하면 부모와 똑같은 자식 프로세스가 생김.
-> 자식 프로세스가 특정 page를 복사할 때 fork()를 함.