개발자 끄적끄적

가상메모리(1) 본문

운영체제

가상메모리(1)

햏치 2024. 5. 22. 18:57

<배경>
- "현재 실행되고 있는 코드들은 반드시 물리적 메모리에 존재해야 한다"
  - 앞서 다룬 메모리 관리 기법들의 특징
  
  - 방법
    - 프로세스 전체를 메모리에 적재
      - 가장 손쉬운 방법
    - Dynamic Loading
      - 프로그래머의 특별한 주의와 추가 작업 필요

  - 단점
    - 프로세스의 크기가 물리적 메모리의 크기로 제한





<주소 공간과 물리 메모리>
- 컴퓨터에 설치 가능한 물리 메모리의 한계
  - CPU의 주소 버스 크기에 좌우
  - 32비트 CPU의 물리 메모리 최대량 : 2^32B = 4GB
  - 64비트 CPU의 물리 메모리 최대량 : 2^64B = 2^24TB

- 실제 설치되는 물리 메모리
  - 현재 대부분 8~32GB정도 장착
    - 비용적인 한계






<물리 메모리의 한계>
- 물리 메모리보다 큰 크기의 프로세스는 실행될 수 없다!
- 동시 수행되는 프로세스들의 크기의 총합은 물리 메모리보다 클 수 없다!







<메모리에 모든 내용이 있어야 하는가?>
- 프로그램의 모든 부분이 동시에 요구되진 않음
  - 순차적 실행

- 항상 모든 코드가 메모리에 적재되어 있어야 하지는 않음
  - 오류 상황을 위한 코드
  - 잘 사용하지 않는 기능에 대한 코드
  - 필요 이상으로 할당된 큰 용량의 배열






<그러면 가능한 대안은?>
- 물리 메모리를 보조저장장치로 확장
  - 프로세스를 메모리와 보조장치에 나누어 저장
  - 프로세스를 실행하기에 충분히 큰 메모리가 있다고 착각하게 만드는 메모리 관리 기법

- 스와핑(Swapping)
  - 메모리가 부족할 때, 실행에 필요하지 않는 부분은 보조저장장치로 이동
  - 실행에 필요할 때 보조저장장치로부터 물리 메모리로 이동






<가상 메모리(Virtual Memory)>
- 물리메모리 영역을 보조저장장치까지 연장
  - 스왑(swap)
  - 무한의 가상적인 메모리 공간

- 실행을 위해 프로세스의 일부만을 메모리에 할당
- 가용 메모리 부족 시 일부 내용을 스왑 영역으로 옮겨 빈 영역 확보
  - 다중 프로그래밍 정도를 높여 CPU 이용률/처리율 향상
  - 스왑-아웃, 스왑-인

- OS 마다 세부 구현 방법은 다름
  - 요구 페이징, 요구 세그멘테이션 등







<일부만 메모리에 적재할 수 있다면?>
- 프로세스의 크기가 물리적 메모리의 크기에 의해 제약 받지 않을 수 있다
  - 프로그래밍 작업이 간단해짐

- 다중 프로그래밍 정도가 늘어남
  - Turnaround time과 response time이 늘어나지 않으면서 CPU utilization과 throughput 향상

- 보다 빠른 실행이 가능
  - 적재 속도의 향상
  - swap을 위한 입출력이 줄어듦






<Process 실행 관련 주요 용어>
- CPU utilization(이용률)
  - CPU가 얼마나 많이 이용되는가

- Throughput(처리량)
  - 단위 시간 동안 수행이 완료된 프로세스 개수

- Turnaround time(총 처리 시간)
  - 임의의 프로세스를 수행하는데 걸리는 시간

- Response time(응답 시간)
  - 요청을 보낸 후 첫 응답이 발생하기 까지 걸린 시간






<Virtual Memory 사용의 기본적인 이점>
- 프로세스간의 메모리 공유를 가능하게 한다
  - 각 프로세스는 각자 자신의 주소 공간을 사용하는 것처럼 보인다
  - 여러 프로세스 간에 시스템 라이브러리를 공유

- 프로그램 실행 중에 사용되는 메모리의 양/배치 방법 등에 대해 신경쓰지 않아도 된다
  - 무한의 메모리라 가정 가능

- 메모리 계층 구조에서 높은 access rate와 비트 당 낮은 저장 비용(low cost per bit)위해






<가상 메모리 시스템의 주요 동작>
- 프로세스의 처리 요구에 따라 서로 다른 레벨의 메모리 간의 정보 블록들의 스와핑

- 주요 결정 사항
  - 인출 정책(Fetch policy) : 언제 가져올 것인가?
  - 배치 정책(Placement policy) : 어디로 가져올 것인가?
  - 교체 정책(Replacement policy) : 어느 frame과 교체할 것인가?






<가상 메모리 관련 문제들>
- 가상 메모리의 페이지 테이블 구성
- 페이지 폴트
- 페이지 할당
- 스왑 영역
- 프레임 할당
- 스레싱
- 작업 집합
- 페이지 교체 알고리즘
- 쓰기 시 복사







<요구 페이징(Demand Paging)>
- 필요한 page들만 물리 메모리에 적재하는 방법
  - 실행중에 page들이 실제 필요할 때에 적재된다
  - 사용되지 않는 page는 적재되지 않음
  - 페이지를 갖는 보조기억장치 영역 : 실행파일 + 스왑

- 장점
  - Less I/O needed
  - Less memory needed
  - Faster response
  - More users
 
 
 
<요구 페이징의 구성>









<스왑(swap) 영역>
- 메모리가 부족할 때, 메모리를 비우고 페이지를 저장해두는 하드 디스크 영역
  - 리눅스 : swap 파티션
  - MS-Windows : C\pagefile.sys 파일

- 스왑-인(swap-in)
  - page-in 이라고도 부르며, 스왑 영역에서 한 page를 메모리 frame으로 읽어들이는 행위

- 스왑-아웃(swap-out)
  - page-out 이라고도 부르며, 메모리 frame에 저장된 page를 스왑 영역에 저장하는 행위






<가상 메모리에서의 페이지 테이블>
- valid/presence bit
  - 해당 page가 물리 메모리에 있는지 여부
    - 1 : 해당 page가 frame 번호의 메모리에 있음
    - 0 : 해당 page가 디스크에 있음

- modified bit(dirty bit)
  - 해당 page가 수정되었는지 여부
    - 1 : 해당 page가 수정되었는지 여부
      - 스왑 아웃될 때 스왑 영역에서 저장 필요

     - 0 : 해당 page는 수정된 적이 없음
      - 스왑 아웃될 때 스왑 영역에 저장 불필요






<페이지 부재(Page Fault)>
- 메모리에 없는 page가 참조할 때 페이징 하드웨어가 OS에게 보내는 trap

- Page fault에 대한 처리 과정
  1. 프로세스에 대한 page table을 통해 해당 참조가 유효한지 검사
    - Invalid reference => abort
    - Just not in memory => 디스크에서 가져와야 함
  2. Free frame을 찾아 디스크로부터 page를 가져옴
  3. Page table 갱신
  4. Page fault에 의해 중단된 intrsuction 재실행
 
 
 
<페이지 부재 처리 과정>








<중단된 Instruction의 재실행>
- Demand paging을 위한 필수적 요구사항

  - 일반적으로 중단된 프로세스의 상태를 나타내는 각종 레지스터들의 값을 저장해두었다가 복원

  - Instruction fetch시 발생된 경우
    - 해당 page를 메모리로 가져온 후 다시 시도

  - Operand fetch/execution시 발생된 경우
    - 해당 page를 메모리로 가져온 후, 해당 instruction을 다시 인출하여 실행
    - 반복 작업이 수반되나 감수할 만함






<가상 메모리에서 새 프로세스 생성>
- fork() 시스템 호출로 생성되는 프로세스
  - 메모리 할당 + 페이지 적재

- fork() 시스템 호출
  - 방법 1 : 완전 복사
  - 방법 2 : 쓰기 시 복사






<방법 1 : 완전 복사>
- 부모 프로세스의 모든 페이지를 온전히 복사
- 많은 경우 fork() 후 바로 exec() 하기에 비효율적
  - ex)
int childPid == fork(); //쉘을 복제한 자식 프로세스 생성
if(childPid == 0){ //자식 프로세스 코드
execlp("/bin/ls", "ls", NULL); // /bin/ls 파일을 적재하여 실행
} // execlp()에 의해 자식 프로세스의 메모리가 모두 반환되고 실행 파일 ls로부터 새로 페이지 적재






<방법 2 : 쓰기 시 복사(Copy-on-Write, COW)>
- 자식 프로세스를 위해 부모의 page table만을 복사
  - 초기에 자식은 부모의 메모리 frame을 온전히 공유

- 자식의 page table 항목에 COW(쓰기시 복사)표시를 해둠

- 부모/자식 중 하나에서 page 수정이 발생하면 새 frame 할당하고 부모 frame복사






<COW의 특징>
- 효율적인 프로세스 생성이 가능
  - 프로세스 생성 시간 절약
    - 전체 page들을 복사하지 않고 단지 변경되거나, 변경 가능한 page들만 복사
    - fork() 후 exec() 발생 시 불필요한 복사 시간의 낭비가 생기지 않음

  - 메모리 절약
    - 수정이 발생되지 않는 page는 새 frame을 할당할 필요 없음 
      - 예 : 코드 영역






<요구 페이징 관련 이슈>
- 페이지 부재가 빈번히 발생시 빈번한 입출력으로 시스템 성능이 떨어지지 않을까?
  - 그럴 수 있다 : 스레싱(thrashing)

- 실행 시 페이지 부재가 계속되면 해당 프로세스의 많은 page가 적재되는데, 애초부터 적재하지 않나?
  - 실행 과정에서 참조될 수 있는 page를 미리 알 수 없기에 

- 한 프로세스에게 할당 가능한 frame은 무한한가?
  - 물리 메모리 양의 크기로 제한됨

- 한 프로세스에게 할당하는 frame 수와 페이지 부재의 관계
  - 일반적으로 반비례 관계

- 커널 코드와 커널 데이터가 적재된 frame도 스왑-아웃되나?
  - 실행 효율성 때문에 이 둘은 항상 물리 메모리에 적재







<스레싱(Thrashing)>
- 프로세스가 실제 실행보다 더 많은 시간을 페이징 처리에 할당하고 있는 상태
  - 과도한 page 교체로 인한 swap in/out에 몰두

- 원인
  - 프로세스가 실행에 필요한 충분한 frame을 할당받지 못하면
    - page fault가 매우 낮아짐
    -> CPU 이용률이 낮아짐
    -> OS는 다중 프로그래밍 정도를 증가시키려 함
  - 악순환 반복으로 심각한 성능 저하 초래







<스레싱 현상>
- 다중 프로그래밍 정도가 높아질수록 CPU 이용률 증가
- 다중 프로그래밍 정도가 임계점(M)을 넘어가면 스레싱 발생








<스레싱 해결 및 예방>
- 감지 방법
  - OS마다 다름
    - MS 윈도 : process explore 등 사용
    - 리눅스 : top, htop, vmstat 명령
  - 작업 부하는 높지만 CPU 이용률이 낮고, 스왑-인/아웃이 모두 높은지 검사

- 해결 및 예방
  - 다중 프로그래밍 정도 줄이기
    - 일부 프로세스 종료
  - 빠른 보조저장장치의 사용
  - 물리 메모리 증가







<참조의 지역성(reference of locality)>
- CPU가 짧은 시간 범위 내에 일정 구간의 메모리 영역을 반복적으로 참조하는 경향
  - locality(지역성), principle of locality(지역성의 원리)
    - 프로그램이 가진 기본적인 실행 특성
 
  - 짧은 시간 동안에는 메모리에 균일하게 접근하기보다는 특정 부분에 집중 참조하는 경향을 지님
    - 프로세스는 최근에 참조한 데이터와 코드를 다시 참조하는 경향성
    - 참조의 지역성 이동. 프로세스가 실행되는 동안 메모리 영역을 옮겨 다니면서 참조의  지역성이 나타남
 
  - 경험적 관찰에서 발견된 90/10 규칙
    - "프로그램 코드의 10%에서 실행 시간의 90% 소비"








<참조의 지역성의 형태>
- 시간 지역성(temporal locality)
  - 시간적으로 볼 때, 
    - 프로세스에서 현재 참조된 주소(페이지)가 가까운 미레에 다시 참조될 가능성이 큰 특성
    - 코드나 데이터, 자원 등이 짧은 시간 내에 다시 사용되는 특성 : 반복문

- 공간 지역성(spatial locality)
    - 공간적(메모리 주소)으로 볼 때,
      - 현재 참조되는 번지(페이지) 주변의 번지들이 가까운 미래에 참조될 가능성이 큰 특성
      - 순차적 실행, 배열, 순차 읽기/쓰기






<참조의 지역성의 의미>
- 현재 프로세스의 실행 패턴을 관찰하면
  - 가까운 미래에 어떤 페이지에 접근할 것인지 합리적으로 예측 가능
 
- 메모리 할당과 페이지 교체 전략에 활용







<작업 집합(working set)>
- 일정 시간 범위 내에 프로세스가 참조한 페이지들의 집합
  - 현재 프로세스의 실행에 필요한 페이지들의 집합
    - 작업 집합에 포함된 페이지들이 모두 메모리에 적재되어 있는 것이 프로세스 실행 최고 성능
  
  - 참조의 지역성으로 작업 집합은 뚜렷이 형성됨
    - OS는 프로세스에게 작업 집합을 적재할 수 있는 정도의 메모리 할당할 필요가 있음
      - 부족 시 잦은 스와핑 발생







<작업 집합과 시간 범위>
- 페이지 부재는 작업 집합을 메모리에 적재하는 과정
  - 참조의 지역성으로 인해 일정 시간 내에 작업 집합 형성
  - 시간 범위가 클수록 작업 집합도 큼
    - 시간 범위를 얼마로 정할 것인가?







<작업 집합 이동(working set shift)>
- 스레싱이 아닌 경우 page fault rate는 시간에 따라 고점과 저점 사이를 오르내림
  - 고점 : 새로운 지역으로 진입










<스레싱과 작업 집합>
- 스레싱 발발 원인 설명에 작업 집합 모델 활용
  - 1968년 Denning의 논문(Thrashing : its causes and prevention)
    - 스레싱의 원인 설명에 '작업 집합' 모델 사용
      - 처음 스레싱 관측
      - 1968년 처음으로 작업 집합 모델로 스레싱 현상을 설명

- 스레싱 예방
  - 스레싱은 작업 집합이 메모리에 올라와 있지 않을 때 발생
  - 1968년 Denning, 실험으로 증명
    - 예방책 제시 - 각 프로세스에게 작업 집합에 포함하는 페이지들을 적재할 충분한 메모리 할당

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

가상메모리(2)  (0) 2024.05.30
비연속 메모리 할당  (0) 2024.05.17
메모리 관리  (0) 2024.05.10