2016년 7월 17일 일요일

Virtual Memory

Virtual Memory


1.   Back Ground
·       프로세스 전체를 메모리에 올리지 않고도 실행이 되도록 한다. -> 메모리 크기보다 큰 프로그램 수행 가능해 진다.
·       프로세스 실행 시, 전체 프로세스가 항상 메모리에 있어야 하는 것은 아니다.(ex) 발생 빈도 낮은 예외 처리 루틴 등)
·       실제의 물리 메모리와 논리 메모리 개념을 분리하여 사용한다.
·       Page 단위로 swap in & swap out이 이루어 진다.(by pager)
2.   Demand Paging
·       그때그때 필요한 page를 메모리로 올리자.
·       Pager(Lazy swapper) : 해당 page가 필요하기 전까지는 올리지 않는다.( cf - swap은 프로세스를 대상으로 이루어짐.)
·       I/O 감소, 메모리 사용량 감소, 빠른 반응속도, throughput, utilization 증가.
·       이를 위해 어느 페이지가 메모리에 있는지 알아야 한다 -> Valid-Invalid Bit를 사용.
o   Valid : in memory
o   Invalid : not in memory or not legal (메모리에 없거나, 디스크 값이 갱신되었음 ex) 공항 예약 시스템)
·       기존 paging에서는 protection을 위해 사용되었음.
o   처음에는 전부 Invalid로 초기화.(안 올라와 있으므로)
o   접근하고자 하는 page table의 항목이 Invalid라면, page fault trap 발생.
·       Pure demand paging : 필요하기 전까지는 swap in x, 메모리에 page를 올리지 않고 프로세스를 시작하는 방법.

·       Page fault
·       Invalid page 접근 시 MMU trap(page fault trap) 발생. -> page fault handler 수행.
o   Page fault 발생시, OS PCB page table을 보고, invalid reference인지 검사.(protection 침해 여부 등.)
1-1) invalid reference 라면 프로세스 중단.
1-2) not in memory 라면, frame을 찾는다.(없다면 replace) + processwait 상태로 만든다.(I/O 해야하니까)
 2)  디스크로부터 page를 읽어와 해당 frame에 넣는다. I/O 종료 후 process ready 큐로 이동하여, dispatch를 기다린다.
 3)  page table의 값을 갱신한다.(invalid -> valid, frame number )
 4)  해당 process가 다시 CPU를 받으면, Page fault trap이 종료된다.
 5)  page fault를 발생시켰던 instruction부터 다시 수행한다.
·       Page fault : instruction fetch 중 발생했다면, page 올린 후 다시 수행하면 돼.
                operand(피연산자) fetch 중 발생, page 올린 후, 해당 instruction 다시 fetch 하면 돼.(restart)
                많은 메모리 공간에 변화를 가져오는 instruction 수행 중 발생. -> undo(이전 상태 기록 임시저장공간 필요)
                -> consistency 위해서 atomic 하게 수행되어야 한다.

·       Performance of demand paging
·       Page fault rate p, [0,1] ( p = 0  page fault x, p =1 모든 접근이 page fault 발생)
·       EAT = (1-p)*memory access time + p*{page fault 오버헤드(disk I/O, 필요 시 replace, swap in, restart overhead)} 
  -  p를 줄이는 것이 아주 중요하다.(Locality 때문에 그렇게 자주 발생하지 않음.)
  -  또한, 메모리의 크기가 커질수록 page fault 빈도가 낮아진다.

·       Process Creation
·       Virtual memory 사용시의 장점.
o   메모리 사이즈 보다 큰 프로세스를 실행 할 수 있다.
o   응답 시간, 쓰루풋 등 지표 개선.
o   Process creation에 걸리는 시간 대폭 감소
o   메모리 공유 율 상승
·       Copy-on-Write(COW) : 프로세스 생성시, fork를 쓰면 부모의 주소공간을 그대로 복사해서 자식의 주소공간을 만들었다.
COW 방식에서는 자식이 부모의 page를 함께 사용하도록 한다. (Page table을 공유하도록 한다.)
만약, 한 프로세스가 shared page를 변형한다면, 그때 해당 page를 복사한다.( 프로세스 생성 시간 대폭 감소)
+) 단순한 page sharing과 다르다. Code 부분 등의 read-only 부분만 공유하는 것이 아니라, 주소 공간 전체를 공유(data까지 공유)하다가, COW를 통해 공유되지 않을 페이지만 새로 만드는 것이므로 공유 율이 훨씬 높다.

·       Page replacement
·       궁극적 목표 : page fault 를 최소화 하는 것.
·       Dirty bit(modify bit) : 해당 페이지가 메모리 위에서 update 되었는지에 대한 정보를 갖고 있어야, DISK I/O 횟수를 줄일 수 있음. 다른 조건이 모두 동일하다면, update가 되지 않은 페이지를 선택하는 것이 유리.
     1) 디스크에서 페이지의 위치를 찾는다.
     2) frame을 찾는다.
2-1) frame이 없다면, 페이지 교체 알고리즘을 수행하여, victim frame을 선정한다. 
     3) victim frame을 디스크에 기록하고, 관련 테이블 변경한다.(invalid, frame..)
     4) 페이지를 frame에 기록하고, 관련 테이블 변경한다.
     -> 이와 같은 page fault service routine 수행 후, CPU 스케줄링 재개.

·       1] FIFO : 일반적으로, Frame 수가 늘어나면, page fault 가 감소해야 하지만 FIFO 사용시 오히려 증가하는 현상 발생.
            (벨러디의 모순)
·       2] OPTIMAL : 앞으로 가장 오랫동안 사용되지 않을 페이지를 선택. (미래 정보를 알 수 없다. 근사하기 위해 LRU 사용)
·       3] LRU : 가장 오랫동안 사용되지 않은 페이지를 선택.(최근 선택된 페이지 남긴다. - Locality)
o   각 페이지 별로 시간정보 저장 필요, victim 선정 시 page list 탐색 필요. -> 시간, 공간 오버헤드 발생.
·       Counter : CPU가 메모리 접근 시마다 counter 값 증가시켜서, 해당 페이지에 기록. 가장 적은 counter 값 가진                                        
              page 선택 -> 시간, 공간 오버헤드 너무 크다.
·       Stack     : page number의 스택을 이중연결리스트로 구현. 사용되는 페이지 번호는 스택의 top, 가장 오랫동안   
             사용되지 않은 페이지 번호는 스택의 가장 밑에 위치. (victim selection O(1))
   -> 공간 오버헤드 발생, 연결리스트에서 찾는 오버헤드 발생, 연결리스트 구조 변화에 오버헤드 발생.
·       4] LRU 근사 알고리즘.
o   Reference bit : 초기 값 0, 페이지가 참조되면 1로 바꾼다. bit 0인 페이지 선택.
-> bit 0 page간에 순서를 알 수 없음.
·       additional reference bit  : reference bit + 추가 8bit 를 사용. 가장 작은 값을 갖는 페이지 선택.
·       일정 주기마다 비트 값을 오른쪽으로 shift 한다.(reference bit -> 8bit)
·       계속 참조 되었다면 all 1, 계속 안 되었다면 all 0.
·       Frequency, 누가 더 최근에 참조 되었는지도 알 수 있음.
·       Second chance(clock) : reference bit + page 원형 큐 사용. 이 비트가 0인 페이지 선택.
·       순환하면서 1 -> 0, 포인터가 한 바퀴 돌 동안 참조되었다면 교체되지 않는다.
-> 최악의 경우(전부다 1인 경우) FIFO가 된다. BUT, locality 때문에 이런 일은 없을 것이다.
·       Enhanced second chance  : reference bit + page 원형 큐 + dirty bit 사용.
·       참조도 안되었고, 변경도 안된 페이지 우선 선택, 참조도 되고 변경도 된 페이지는 가장 후 순위.
·       5] 참조 횟수 count 알고리즘
o   LFU : count 수가 가장 작은 페이지 선택. But, locality의 변화에 대처 어려움.
o   MFU : count 수가 가장 큰 페이지 선택. 말도 안됨.

·       Allocation of frames
·       프로세스에게 프레임을 어떻게 할당할 것인가?(총 몇 개의 frame을 사용할 수 있도록 할 것인가?)
·       Minimum number of frames
o   한 명령어가 참조하는 모든 페이지는 동시에 메모리에 올라와야 instruction 수행 가능.
o   loop내의 page 는 동시에 올라와 있는 것이 유리( loop마다 페이지 폴트 발생 -> disk I/O,,,)
·       Fixed allocation : 프로세스에게 한번 할당한 공간의 크기는 끝까지 바뀌지 않는다.
o   Equal allocation : 모든 프로세스에게 동일한 크기 할당.
o   Proportional allocation : 프로세스의 크기에 비례하여 할당.
·       Priority allocation : 우선순위에 비례하여 할당.
o   높은 우선순위를 갖는 프로세스는 더 많은 메모리를 가지므로 페이지 폴트 수 감소, I/O 감소, 더 빨리 끝난다.
o   I/O가 줄어드니까 waiting state에서 보내는 시간이 줄어들고, 일찍 끝난다.
o   페이지 폴트가 발생 했다면
·       Victim을 해당 프로세스에 할당된 frame 내에서 선택 -> local replacement
·       Victim은 어떤 프로세스에서도 선택 가능(낮은 우선순위 프로세스의 frame 뺏기 가능) -> global replacement
-> 지역 교체에서는, 잘 안 쓰이는 페이지 프레임이 있어도 계속 낭비하게 됨. 전역 교체가 더 좋다.

·       Thrashing
·        페이지 폴트가 너무나도 빈번히 발생하여 예기치 못하게 성능이 급격히 하락하는 현상.
·        페이지 폴트 많이 발생 -> handler 호출 -> disk I/O 자주 발생 -> I/O 대기시간이 대부분의 시간을 차지하게 된다.
 -> CPU가 유의미한 일을 하지 못함. -> long term scheduler CPU 이용률을 높이기 위해 새로운 프로세스 올린다.
 -> 페이지 폴트 증가 -> CPU 이용 률 감소….     +) degree of multiprogramming : 메모리에 있는 프로세스의 수
·       Thrashing은 순식간에 발생. Frame 1개 차이로 발생할 수 있다.
·        paging은 왜 동작할까?
o   Locality 때문, CPU의 메모리 접근에는 지역성이 존재하기 때문.
·       Thrashing은 왜 생길까?
o   어떤 프로세스가 새로운 지역을 진입할 때, 충분한 frame을 제공해 준다면, 그 지역의 모든 페이지가 올라올 때 까지는 페이지 폴트가 발생하지만, 그 이후 그 지역을 떠나기 전까지는 발생하지 않는다. But, 그 지역의 페이지 수 보다 적은 프레임을 할당하면, 이 지역을 수행하는 동안 계속해서 페이지 폴트를 발생 시킨다. -> 쓰레싱.
o   Total size of locality > total allocated memory size 일 때, thrashing 발생.
o   +) virtual memory 쓰지 않는다면, 실행중인 프로세스의 페이지는 모두 메모리 위에 있으므로, 페이지 폴트, 쓰레싱 x.











  8-1. Locality
·       프로그램의 메모리 참조는 고도의 지역성을 가진다.
o   시간 지역성(temporal locality) : 현재 참조된 메모리가 가까운 미래에도 참조될 가능성이 높다. (ex - loop)
o   공간 지역성(spatial locality) : 현재 참조된 메모리의 주변 메모리가 계속 참조될 가능성이 높다. (ex - array traversal)

  8-2. Working set model
·       Locality를 토대로 한 모델, allocation, replacement등에 사용할 수 있다.
·       Δ = working set window, 시간간격을 의미(Δ 동안 참조된 page를 보겠다)
·       WS(ti) = ti working set, [ti, ti-Δ] 동안 접근한 페이지의 집합.
o   Δ가 너무 작으면, locality를 제대로 반영하지 못함.
o   Δ가 너무 크다면, 여러 지역성을 과도하게 수용.
o   Δ가 무한대라면, 이제껏 참조한 전체 페이지의 집합.
-> 잘 정하는 것이 중요하다, 이게 안 되서 못쓴다.
·       WSSi = Pi working set size, D = WSSi (전체 프레임 요구량), m = 사용가능한 전체 프레임의 수
o   D > m  -> thrashing 발생. 
o   OS는 각 프로세스의 Working set을 보면서, 각 프로세스의 working set size에 맞는 프레임 들을 할당한다. 프레임이 남는다면 새로운 프로세스를 시작시킨다.(d.o.m 증가) but, D m보다 커진다면 OS는 프로세스를 하나 선택해서, suspend 시킨다.
o   WS(ti)가 모두 보장되어야만 run, 아니면 suspend.
·       실제 구현
o   reference 마다 각 page의 최근 접근시간이 Δ안에 들어가는지 검사해야 한다. -> 너무 오버헤드 크다, 근사하자.
o   Reference bit + interval timer + additional 2 bits
·       Δ 10k라면, 5k마다 timer interrupt 발생하여 비트를 left shift, reference bit 0으로 만든다.
·       3 비트 중 1개라도 1이라면 10k내에 참조가 되었다는 것을 의미.(working set 내에 속한다.)
·       오차가 존재한다.(맨 왼쪽 비트는 10001~14999 의미 가능, working set size보다 커진다.)
·       비트 수를 눌리고 interval을 줄이면 (ex - 10, 1k) 오차 줄일 수 있음.
-> 매 참조시마다 값을 계속 변경시켜야 하므로 오버헤드가 너무 크다.

8.3. page fault frequency scheme
·       실제 페이지 폴트 발생 비율을 보고 프레임 할당을 조정하자.
·       Upper bound보다 높으면, 프레임을 더 할당한다.(free frame이 없으면 프로세스를 선택하고 suspend)
·       Lower bound보다 낮으면, 프레임을 감소시킨다.
-> PFF는 페이지 폴트시에만 페이지 집합을 수정하므로 오버헤드가 훨씬 적다.

·       Memory mapped files
·       Virtual memory side benefits 1) process creation 오버헤드 대폭 감소. 2) file I/O 오버헤드 대폭 감소.
·       일반적인 File I/O file system을 거치는 과정에서 수많은 system call들을 거쳐야 한다.
·       Memory mapped file에서는 file address spacemapping 시킨다. CPU는 파일이 메모리에 올라와 있다고 여기므로, Logical address를 발생시켜서 접근하려고 한다.(load, store를 쓴다, read, write x, file system을 거치지 않는다.)
·       CPU가 요구하면, 실제로는 메모리에 없으니까 page fault가 발생하고, 실제로 파일을 메모리에 올린다. 최악의 경우 전체 file이 메모리에 올라오게 된다. (# of page fault = entire file size / page size)
·       파일을 메모리에 올릴 때, page 단위로 올리므로 Disk I/O가 줄어든다.(접근 단위가 1 BYTE라도 페이지 폴트 수는 불변)
 -> 장점 : Disk I/O가 줄어든다(한번 페이지 단위로 올라오고 난 이후의 접근은 memory access이다)
             여러 프로세스가 파일을 공유할 수 있다.
 -> 단점 : 파일 값 변경 시, 디스크가 아닌 메모리에 반영한다.(메모리에서 쫒겨날 때 or 의도적으로 동기화 할 때 반영)

·       Other issue
1.   Prepaging : 프로세스의 시작 때 발생하는 과한 page fault를 줄이자!
·       미리 필요한 page 들을 메모리에 올려둔다. 만약 쓰이지 않는 다면 불필요한 I/O, 메모리 사용 발생하므로 잘 정해야 한다.
2.   Page Size
·       Page size가 커지면
o   Page table 크기 감소
o   Page 개수 감소
o   TLB 감소
o   Disk I/O 효율 상승(한번에 많은 데이터를 가져오므로)
  BUT, internal fragmentation 증가.
·       TLB reach : TBL를 통해 접근할 수 있는 메모리의 크기. TLB reach = TLB size(entry ) * Page size
·       Working set TLB내에 모두 저장될 수 있으면 이상적. 그렇지 않으면 TLB miss, 메모리 접근 필요.
·       Page size를 증가시키면, internal fragmentation 커진다. TLB size 증가는 너무 비싸다.
·       대안 ) 다양한 page size를 사용.
·       Program structure : P.L row major 인지 column major인지에 따라 코드에 따른 페이지 폴트 수가 급증할 수 있다.
·       I/O interlock : I/O의 대상이 될 페이지는 교체 대상으로 보지 않아야 한다.


댓글 없음:

댓글 쓰기