1 물리 메모리의 한계
1.1 주소 공간과 물리 메모리
- 32비트 CPU가 액세스할 수 있는 물리 메모리의 최대 크기 = = 프로세스의 주소 공간
- 사용자가 작성할 수 있는 응용프로그램(프로세스)의 최대 크기는 프로세스 주소 공간 중 운영체제가 설정한 사용자 공간의 크기
2 가상 메모리 개념
2.1 가상 메모리 개요(virtual memory)
- 물리 메모리보다 큰 프로세스나 여러 개의 작은 프로세스를 동시에 실행시켜, 사용자나 응용프로그램에게 무한대의 메모리가 있다고 느끼도록 하는 메모리 관리 기법
- 핵심
- 물리 메모리를 디스크 공간으로 확장
- 스와핑(swapping)
가상 메모리 개념
- 물리 메모리의 영역을 하드 디스크까지 연장, 프로세스를 물리 메모리와 하드 디스크에 나누어 저장한다.
- 프로세스의 실행에 필요한 부분만 메모리에 적재하고 나머지는 하드 디스크에 저장해두고 실행에 필요할 때 물리 메모리로 이동시킨다.
- 물리 메모리에 빈 영역이 부족하게 되면, 운영체제는 프로세스를 구분하지 않고 물리 메모리의 일부분을 하드 디스크에 옮겨 물리 메모리의 빈 영역을 확보한다.
- 물리 메모리를 확장하여 사용하는 디스크 영역을 스왑 영역(swap area), 물리 메모리의 일부를 디스크로 옮기는 작업을 스왑-아웃(swap-out), 스왑 영역으로부터 물리 메모리로 적재하는 과정을 스왑-인(swap-in)
- 프로세스는 0번지부터 연속적으로 존재한다고 생각하며, 어떤 부분이 어디에 있는지(물리 메모리인지, 하드 디스크 인지) 알지 못한다.
- 가상 메모리는 운영체제마다 구현 방법이 다르다.
논리 주소와 가상 주소
논리 주소 = 가상 주소(virtual address) 컴파일러 입장에서 보면 논리 주소가 적합하지만, 운영체제 입장에서는 가상 주소라고 부르는 것이 더 적합
TIP
malloc()이 메모리가 부족하여 null을 리턴하는 경우, 물리 메모리가 부족한 것인가? 아니다. 프로세스의 사용자 주소 공간 내에 힙 영역이 부족해서 그런것
2.2 가상 메모리 구현
운영체제에서 다음 2가지 방법으로 구현
- 요구 페이징(demand paging)
- 페이징 기법을 토대로 프로세스의 일부 페이지들만 메모리에 적재하고 나머지는 하드 디스크에 둔다.
- 페이지가 필요할 때 메모리를 할당받고 페이지를 적재시키는 메모리 관리기법
- 요구페이징 = 페이징 + 스와핑
- 요구 세그먼테이션(demand segmentation)
- 세그먼테이션 기법을 토대로 한다.
- 프로세스를 구성하는 일부 세그먼트들만 메모리에 적재해두고, 다른 세그먼트가 필요할 때 메모리를 할당받아 세그먼트를 적재하는 메모리 관리 기법
3 요구 페이징(demand paging)
3.1 요구 페이징 개념
- 물리 메모리의 크기 한계를 극복하기 위해 페이징 기법을 기반으로 만들어진 가상 메모리 기법
- 페이지가 필요할때 물리 메모리를 할당받고 디스크에서 읽어 적재
3.2 요구 페이징 구성
디스크의 스왑 영역
- 메모리에서 쫓겨난 페이지들이 저장되는 영역
- 스왑 영역을 구성하는 방법은 운영체제마다 다르다
- 디스크 내에 특정 위치를 정해서 사용
- 스왑 파티션
- 특정 파일
페이지 테이블
- presence/valid 비트 - 페이지가 메모리에 적재되어 있는지를 나타내는 비트
- 1 - 물리 메모리
- 0 - 디스크
- modified/dirty 비트 - 페이지가 메모리에 적재된 후 수정되었는지를 나타내는 비트
- 1 - 물리 메모리에 적재된 후 수정됨
- 0 - 수정된 적 없음
- physical address 필드
- presence = 1 - 물리 프레임의 번호
- presence = 0 - 디스크 주소(디스크 블록 번호, disk block number)
페이지 폴트(page fault)
CPU가 가상 주소를 발생시켜 액세스하려는 페이지가 현재 물리 메모리에 없을 때 페이지 폴트라고 한다.
3.3 페이지 폴트 자세히 알기
; n = 10을 컴파일한 코드
mov eax, 10 ; eax 레지스터에 10 저장
mov [11111234], eax ; eax 레지스터 값을 0x11111234 번지에 저장
3.4 요구 페이징 시스템에서 프로세스 실행
- 프로세스의 시작 페이지 적재 메모리 프레임 1개 할당, 실행 파일로부터 프로세스의 실행이 시작될 첫 페이지를 적재한 후 실행
- 여러 번의 페이지 폴트를 통해 실행 파일로부터 페이지들 적재
프로세스의 실행 초기에는 전역 변수가 담긴 페이지나 스택 페이지가 메모리에 없기 때문에 페이지 폴트가 연이어 발생
- 폴트가 발생한 페이지는 실행 파일 또는 스왑 영역 중에 있다.
- 메모리가 부족하면 스왑-아웃/스왑-인
- 스왑-아웃된 페이지 100을 다시 스왑-인
- 수정된 페이지는 스왑 영역에 쓰기
빈 프레임을 만들기 위해 희생 페이지를 선택했을 경우
- 페이지 테이블 항목에 M비트=1 이라면, os는 해당 페이지가 들어 있는 프레임을 스왑 영역에 다시 기록
- M비트=0 일 경우, 적재된 후 수정X, 해당 페이지가 있던 프레임에 다른 페이지 적재
순수 요구 페이징
아무 페이지도 적재하지 않은 채 프로세스를 실행, 페이지 폴트를 통해 첫 페이지를 적재
가상 메모리에 스왑 영역은 꼭 필요할까?
필요하다. 스왑 영역을 디스크의 정해진 위치에 만들고 이용하면 일반 파일 시스템에서 읽고 쓰는 속도보다 훨씬 빠르다.
요구 페이징에서 프로세스의 각 영역에 대한 적재 및 스왑 정리
영역 | < | 처음 액세스 | 적재 후 M 비트 값 | 처음 액세스 후 교체될 때 | 다시 액세스 될 때 |
---|---|---|---|---|---|
코드 | < | 프레임 할당. 실행 파일로 부터 적재 | 항상 0(읽기 전용) | 항상 프레임 버림 | 프레임 할당. 실행 파일로 부터 적재 |
데이터 | 초기화된 데이터 | 프레임 할당. 실행 파일로부터 적재 | 0 | M비트=1→스왑-아웃 M비트=0→프레임 버림 | 스왑 영역에 있으면 스왑-인. 없으면 실행 파일로부터 적재 |
^ | 초기화되지 않은 데이터 | 프레임 할당. 0으로 초기화 | 1 | M비트=1 이므로 스왑-아웃 | 스왑 영역에서 스왑-인 |
힙 | < | 프레임 할당. 초기화 없음 | 0 | M비트=1→스왑-아웃 M비트=0→프레임 버림 | 스왑 영역에 있으면 스왑-인. 없으면 다시 프레임 할당 |
스택 | < | 프레임 할당. 초기화 없음 | 0 | M비트=1→스왑-아웃 M비트=0→프레임 버림 | 스왑 영역에 있으면 스왑-인. 없으면 다시 프레임 할당 |
3.5 쓰기 시 복사(COW, copy on write)
완전 복사
int childPid = fork(); // fork() 시스템 호출로 현재 프로세스를 복사한 자식 프로세스 생성
- 부모 프로세스의 메모리를 모두 복사하여 자식 프로세스 생성
완전 복사의 비효율성
리눅스의 쉘을 비롯하여 많은 응용프로스램들은 fork()로 자식 프로세스를 생성한 후 자식 프로세스가 execlp()을 이용하여 곧 바로 다른 프로그램(실행 파일)을 실행시키도록 작성된다. 즉 부모 프로세스의 메모리를 모두 복사하여 자식 프로세스가 생성된 직후 할당받은 메모리를 모두 반환하고 다른 실행파일로 부터 다시 페이지를 적재한다는 것
쓰기 시 복사(copy on write, COW)로 완전 복사 문제 해결
- 부모 프로세스의 메모리를 복사하지 않고 자식 프로세스가 부모 프로세스의 메모리를 완전히 공유
- 부모or자식 실행중 메모리 쓰기가 발생하면, 그때 os가 쓰기가 발생한 페이지만 새 프레임을 할당받아 복사
- 읽는 경우 복사X
페이지 테이블 항목
- presence 비트 - 1이면 페이지가 메모리 프레임에 존재. valid bit 라고도 함
- modified 비트 - 1이면 페이지가 적재된 후 수정되었음. dirty bit 라고도 함
- protection 비트 - ‘R’이면 읽기 전용 페이지, ‘RW’이면 읽기 쓰기 모두 가능한 페이지
- reference 비트 - 1이면 페이지가 최근에 참조되었음
- physical address 필드 - 페이지가 저장된 프레임 번호 혹은 디스크 블록 번호
쓰기 시 복사의 장점
- 프로세스 생성 시간 절약
- 부모 프로세스의 메모리 프레임을 복사 X
- 메모리 절약
- 읽기만 하는 페이지는 새로운 프레임 할당 X
3.6 페이지 폴트와 스래싱(thrashing)
페이지 폴트와 디스크 I/O
- 페이지 폴트가 발생하면 필연적으로 디스크 입출력이 동반
- 디스크 입출력을 줄이기 위해 페이지 폴트의 횟수를 줄여야 한다.
스래싱
- 페이지 폴트가 계속 발생하여 메모리 프레임에 페이지가 반복적으로 교체되고 디스크 입출력이 십각하게 증가하고 CPU 활용률이 대폭 감소하는 현상
- 빈번한 페이지 폴트로 인한 디스크 입출력 증가 현상
스래싱 원인
- 다중프로그래밍 정도(메모리 양에 비해 실행중인 프로세스의 개수, degree of multiprogramming)가 과도한 경우
- 메모리 할당 정책이나 페이지 교체 알고리즘이 잘못되었을 경우
- 컴퓨터 시스템에 설치된 메모리가 절대적으로 작은 경우
- 우연히도 특정 시간대에 너무 많은 프로세스를 실행한 경우
스래싱 현상 관찰
동시에 실행되는 프로세스의 개수가 많음에도 불구하고 오히려 CPU 활용률이 갑자기 떨어질 때 스래싱이 발생하기 시작한 것으로 판단할 수 있다.
스래싱 해결 및 예방
스래싱이 발생한 상태
- 몇 개의 프로세스를 강제로 종료시켜 다중 프로그래밍의 정도를 낮추어야 한다. 스래싱을 예방하기 위해서는 다중프로그래밍 정도의 시스템 허용치를 낮추어 설정하거나, RAM을 늘려야 한다.
4 참조의 지역성과 작업 집합
5 프레임 할당
6 페이지 교체
Ref.
황기태, “명품 운영체제”, (주)생튼출판사(2021)