전체 프로그램이 메모리에 있어야 실행될 수 있지만, 전체 프로그램이 동시에 사용되는 경우는 드물다.
따라서 전체 프로그램 코드가 동시에 필요하지 않아, 부분적으로 로드된 프로그램을 실행하는 기능을 고려할 수 있다.
이렇게 하면 프로그램은 물리적 메모리의 제약을 받지 않게 되고, 실행중인 각 프로그램이 더 적은 메모리를 차지하게 되므로 동시에 더 많은 프로그램을 실행할 수 있다.
이는 CPU 이용률과 처리량을 늘리고, 응답 시간이나 완료 시간을 늘리지 않으면서 메모리에 프로그램을 로드하거나 교체하는 데 필요한 I/O를 줄일 수 있다.
Virtual Memory
가상 메모리는 사용자의 논리 메모리와 물리 메모리의 분리를 의미한다.
실행을 위해 프로그램의 일부만 메모리에 있으면 되므로, 논리 주소 공간은 물리 주소 공간보다 훨씬 클 수 있다.
이는 주소 공간을 여러 프로세스에서 공유할 수 있게 해주고 프로세스 생성을 더 효율적으로 만들어주고, 동시에 더 많은 프로그램을 실행하며, 프로세스를 로드하거나 교체하는 데 필요한 I/O를 줄일 수 있다.
Virtual-address Space
가상 주소 공간은 프로세스가 메모리에 저장되는 방식에 대한 논리적인 시각을 제공한다.
보통 0번 주소에서 시작해서 공간의 끝까지 연속된 주소를 사용한다.
물리 메모리는 페이지 프레임으로 구성된다. 메모리 관리 유닛(MMU)은 논리 주소를 물리 주소로 매핑해야 한다. 가상 메모리는 요구 페이징 또는 요구 세그멘테이션을 통해 구현될 수 있다.
보통 스택을 최대 논리 주소에서 시작하게 하여 아래로 성장하게 하고, 힙은 위로 성장하게 함으로 논리 주소 공간을 최대한 활용한다. 두 가지 사이의 미사용 주소 공간을 hole이라고 한다.
시스템 라이브러리는 가상 주소 공간으로 매핑되어 공유된다.
읽기-쓰기로 페이지를 가상 주소 공간에 매핑함으로써 공유 메모리를 구현할 수 있다.
fork()중에 페이지를 공유하여 프로세스 생성 속도를 높일 수 있다.
Demand Paging (요구 페이징)
프로세스에서, 페이지가 필요할 때만 메모리로 가져올 수 있다.
- 필요한 I/O가 적고 불필요한 I/O가 없다.
- 필요한 메모리가 적다.
- 더 빠른 응답 시간을 가진다.
- 더 많은 사용자 기능을 가진다.
Swapping : 전체 프로세스를 메모리로 가져옴
Swapping with Paging : 일부 페이지를 메모리로 가져옴
Demand Paging : 필요한 페이지만 메모리로 가져옴
스왑과 유사한 페이징 시스템으로, 페이지가 필요하면 참조한다.
- 잘못된 참조가 있을 시 abort(중단) 시키고, 메모리에 없으면 메모리로 가져온다.
Valid-Invalid Bit
각 페이지 테이블 엔트리에는 valid-invalid bit가 연결된다.
v이면 메모리에 존재하고, i이면 메모리에 존재하지 않으며, 초기 모든 엔트리는 i로 설정된다.
MMU 주소 변환 중에, 페이지 테이블 엔트리의 valid-invalid bit가 i라면 페이지 폴트가 발생한다.
페이지폴트의 handling 단계는 다음과 같다.
1. 페이지에 참조가 있는 경우, 해당 페이지에 대한 첫 번째 참조는 OS로 trap된다. (page fault)
2. OS는 다른 테이블을 확인해서 결정한다. (invalid reference => abort, 또는 그저 메모리에 없는 경우)
3. 빈 프레임을 찾는다.
4. 예약된 디스크 작업을 통해 페이지를 프레임으로 스왑한다.
5. 페이지가 이제 메모리에 있다는 것을 나타내도록 테이블을 재설정한다. (validation bit = v)
6. 페이지폴트를 일으킨 명령을 다시 시작한다.
major page fault : 페이지가 메모리에 없음
minor page fault : 메모리에 있지만 매핑이 안돼있거나(shared library), 원하는 페이지가 free-frame list에 남아있음
* 메모리에 있지만 매핑되지 않았다는 것은 페이지가 물리 메모리에 존재하지만 현재 실행중인 프로세스의 주소공간에 매핑되지 않았다는 뜻
linux는 minor page fault가 훨씬 많이 발생한다. 이는 shared library를 많이 사용한다는 뜻이다.
Aspects of Demand Paging
극단적인 경우 - 메모리에 페이지가 하나도 없는 상태로 프로세스 시작
- OS는 프로세스의 첫 번째 명령어 주소로 명령 포인터를 설정하고, 메모리를 상주하지 않아 페이지 폴트 발생
- 그리고 다른 프로세스의 페이지는 첫 번째 접근 시에만 메모리에 올라옴
- pure demand paging : 시작할 때 메모리에 어떤 페이지도 없는 방식 (<-> prepaging: 메모리의 일부를 미리 로딩)
실제로는 특정 명령어가 여러 페이지에 접근할 수 있다! => 여러 페이지 폴트 발생
- 참조의 지역성, 현재 참조된 페이지와 연관된 페이지들이 함께 가져와질 가능성이 높아지므로 효율적이다.
demand paging에 필요한 하드웨어 지원
- valid / invalid bit를 가진 페이지 테이블
- 보조기억장치 (스왑 장치와 스왑 공간)
- 명령어 재시작
이때, 블록(연속된 데이터 블록)을 옮긴다고 할 때, 명령어를 재시작 할 때 겹치는 부분에서 손실이 발생할 수 있다.
- 1. 페이지 폴트가 일어나기 전에 미리 페이지를 불러들이고 명령어를 실행한다
- 2. 임시 레지스터에 겹치는 부분을 저장해뒀다가 page fault가 일어나면 restore한다.
최악의 경우의 Demand Paging (page fault 상세 과정)
1. OS로 트랩 발생
2. 사용자 레지스터와 프로세스 상태 저장 (이후 동일한 상태에서 수행될 수 있도록 하기 위해)
3. 인터럽트가 페이지 폴트인지 확인
4. 페이지 참조가 유효하고 디스크 상의 페이지 위치를 결정
5. 빈 프레임으로부터 디스크로 읽기 명령 발생
5-1. 이 장치를 위한 ready queue에 요청 서비스를 위해 대기
5-2. 디스크의 seek(디스크 헤드가 원하는 위치로 이동하는데 걸리는 시간) 및 대기 시간(latency time, 디스크가 해당 데이터를 읽을 때까지 걸리는 시간)을 대기
5-3. 페이지를 빈 프레임으로 전송 시작
6. 대기하는 동안, CPU를 다른 사용자에게 할당
7. 디스크 I/O 서브시스템으로부터 인터럽트를 받음 (I/O 완료)
8. 현재 실행중인 프로세스의 레지스터와 프로세스 상태를 저장
9. 인터럽트가 디스크에서 발생했는지 확인
10. 페이지 테이블과 다른 테이블을 수정해서 페이지가 메모리에 존재함을 표시
11. CPU가 다시 이 프로세스에 할당될 때까지 대기
12. (2번에서 저장된)사용자 레지스터, 프로세스 상태, 새로운 페이지 테이블을 복원하고 중단된 명령을 재시작한다.
Memory Compression
메모리 압축은 수정된 프레임을 스왑 공간으로 페이징 아웃하는 대신, 여러 프레임을 하나의 프레임으로 압축해서 메모리 사용량을 줄이는 방법이다.
위와 같은 상황에서 페이지 교체를 한다면, free-frame list의 수가 page replacement를 유발하는 특정 임계값 이하로 떨어진다고 가정할 때, 페이지 교체 알고리즘은 15, 3, 35, 26 프레임을 modified-frame list에 두고 이들이 스왑 공간에 기록되면 각 프레임을 free-frame list에 추가한다.
그런데 15, 3, 35를 압축했을 때 프레임 하나에 들어갈 수 있다고 하자.
메모리 압축을 통해, 15 3 35 프레임을 7 프레임에 압축해서 저장하고 15 3 35 프레임을 free-frame list에 추가할 수 있다.
안드로이드와 iOS는 swapping, paging없이 메모리 압축만 사용하고 macOS와 윈도우10도 메모리 압축을 지원한다.
Performance of Demand Paging
페이지 폴트의 비율 p는 0 이상, 1 이하의 값을 가진다. (0 <= p <= 1)
EAT = (1-p) * 메모리접근 + p * (페이지폴트 오버헤드 + 스왑페이지 아웃 + 스왑페이지 인)
예를 들어 메모리 접근 시간이 200나노초, 평균 페이지폴트 서비스 시간이 8밀리초라면,
EAT = (1-p)*200ns + p * (8ms) = (1-p)*200ns + p * 8000000ns = 200 + p * 8000000 (ns)
가 된다.
즉 메모리에 1000번 접근할 때 1번 페이지 폴트가 발생하면 40배의 성능 저하가 발생한다.
만약 성능저하가 10% 미만이여야 한다면,
220 > 200 + 7999800 * p
p < 0.0000025
즉, 40만번의 메모리 접근 중 페이지 폴트가 1번 미만 발생해야한다.
Demand Paging Optimizations
스왑 공간 I/O가 파일 시스템 I/O보다 빠르다 - 스왑 공간이 더 큰 덩어리로 할당되어 관리가 덜 필요
프로세스 이미지 전체를 프로세스 로드 시간에 스왑 공간으로 복사, 그 후 스왑 공간에서 페이지를 앞뒤로 이동 (BSD Unix에서 사용됨)
디스크에서 프로그램 이진 파일로 페이지를 요청하되, 프레임을 해제할 때 페이지를 아웃하지 않고 버린다.
- Solaris와 현재 BSD에서 사용중임
- 하지만 스왑 공간에 쓰는 작업이 여전히 필요하다. 파일과 관련이 없는 페이지(스택, 힙 등)와 메모리에서 수정되었지만 아직 파일 시스템에 기록되지 않은 페이지가 그렇다. => 익명 메모리라고 부름
모바일 시스템은 스와핑을 지원하지 않는다. 대신 파일 시스템에서 페이지를 요구하고 읽기 전용 페이지(코드 등)를 회수한다.
Copy on Write
COW는 부모 프로세스와 자식 프로세스가 초기에 메모리에서 동일한 페이지를 공유하게 할 수 있는 전략이다. 만약 어느 한 프로세스가 공유 페이지를 수정하면 그때 페이지가 복사된다.
일반적으로 사용 가능한 페이지는 zero-fill-on-demand 페이지 풀에서 할당받는다. 이 페이지 풀은 페이지 폴트 처리를 빠르게 실행할 수 있도록 항상 free-frame을 유지한다. 이는 페이지 폴트가 발생할 때 프레임을 해제하는 등 추가 처리를 하지 않기 위해서다.
페이지를 할당하기 전에 0으로 채우는 이유는 보안 때문이다. 이전의 데이터가 그대로 남아있으면 그 정보를 잘못 사용할 수도 있기 때문이다.
vfork()는 fork()의 변형으로 부모가 중단되고 자식이 부모의 주소 공간을 copy-on-write 방식으로 사용한다. 이 방식은 linux, macOS, BSD unix 등에서 사용된다. 이 시스템콜은 자식이 exec()를 호출한다.
'학교강의필기장 > 운영체제론' 카테고리의 다른 글
운영체제론[18]: 가상메모리 - 3 (0) | 2023.06.22 |
---|---|
운영체제론[17]: 가상메모리 - 2 (0) | 2023.06.22 |
운영체제론[15]: 메모리 - 2 (0) | 2023.06.22 |
운영체제론[14]: 메모리 - 1 (0) | 2023.06.22 |
운영체제론[13]: 데드락 (0) | 2023.06.22 |