프로그램이 실행되기 위해서는 디스크에서 메모리로 가져와 프로세스 내에 배치돼야한다.
주 기억장치와 레지스터는 CPU가 직접 액세스 할 수 있는 유일한 저장 공간이다.
레지스터 액세스는 CPU클록 안에 이루어지며, 주 기억 장치는 여러 사이클을 소요할 수 있고, 이로 인해 지연이 발생할 수 있다.
캐시는 주 기억장치와 CPU 레지스터 사이에 위치하여 데이터 접근 속도를 향상시킨다.
메모리 장치는 주소의 읽기 요청 또는 주소의 데이터 및 쓰기 요청의 연속으로 작업한다.
메모리의 보호는 올바른 동작을 보장하기 위해 필요하다.
Protection
프로세스의 주소 공간은 프로세스가 접근할 수 있는 주소 범위를 나타낸다. 운영체제는 프로세스가 할당받은 주소 공간 외의 영역에 접근하는 것을 방지해서 메모리 보호를 제공한다. 기준 레지스터는 프로세스의 주소 공간에서의 시작 위치를 가리키며, 한계 레지스터는 주소 공간의 크기를 나타낸다.
사용자 모드에서 실행되는 프로세스의 모든 메모리 액세스는 CPU에 의해 기준과 한계 사이에 있는지 확인된다.
기준과 한계 레지스터를 로딩하는 명령어는 특권이 있는 명령어(privileged)로, 이 레지스터는 OS는 설정할 수 있지만 사용자 프로그램은 변경할 수 없다.
Address Binding
디스크에 있는 프로그램들은 메모리로 가져와 실행하기 위해 입력 대기열을 형성한다. (support 없이는 주소 0000로 로드돼야한다)
프로그램의 생명 주기의 다른 단계에서 주소는 다른 방식으로 표현된다.
- 소스코드 주소는 보통 상징적(symbolic)으로 표현된다.
- 컴파일된 코드 주소는 재배치 가능한 주소에 바인딩된다. (ex. 모듈의 시작으로부터 14바이트)
- 링커나 로더는 재배치 가능한 주소를 절대 주소로 바인딩한다. (ex. 74014)
- 각 바인딩은 한 주소 공간을 다른 주소 공간으로 매핑한다.
명령어와 데이터의 주소 바인딩은 메모리 주소에 대해 세 가지 다른 단계에서 발생할 수 있다.
compile time : 메모리 위치가 미리 알려져 있다면 절대 코드를 생성할 수 있으며, 시작 위치가 변경되면 코드를 다시 컴파일해야한다.
load time : 메모리 위치가 컴파일 타임에 알려지지 않는 경우, 재배치 가능한 코드를 생성해야한다.
execution time : 프로세스가 실행 중에 메모리 세그먼트를 이동할 수 있는 경우, 바인딩은 실행 시간까지 지연된다. - 주소 맵에 대한 하드웨어 지원이 필요하기에(ex. 기준 레지스터, 한계 레지스터) 가상 메모리 개념이 필요하다.
논리적 주소 공간이 별도의 물리적 주소 공간에 바인딩되는 개념은 올바른 메모리 관리에 중요하다.
논리적 주소 - CPU에 의해 생성되는 주소, 가상 주소라고도 불린다.
물리적 주소 - 메모리 장치에서 볼 수 있는 주소
컴파일 타임과 로드 타임의 주소 바인딩 방식에서는 논리적 주소와 물리적 주소가 동일하며, 실행 타임의 주소 바인딩 방식에서는 논리적 주소와 물리적 주소가 다를 수 있다.
논리적 주소 공간은 프로그램에 의해 생성된 모든 논리적 주소의 집합이다.
물리적 주소 공간은 프로그램에 의해 생성된 모든 물리적 주소의 집합이다.
MMU(Memory-Management-Unit) : 실행 시간에 가상 주소를 물리적 주소로 매핑하는 하드웨어 장치
기준 레지스터는 이제 재배치 레지스터(relocation register)로 불린다.
재배치 레지스터에 있는 값은 사용자 프로세스에 의해 생성된 모든 주소에 추가된다. 이는 해당 주소가 메모리로 전송될 때 실행된다.
Dynamic Loading
전체 프로그램이 메모리에 있어야 실행될 필요는 없다.
루틴은 호출될 때까지 로드되지 않는다. - 더 나은 메모리 공간 활용을 위해 사용되지 않는 루틴은 로드되지 않는다.
모든 루틴은 재배치 가능한 로드 형식으로 디스크에 유지된다.
드물게 발생하는 상황을 처리하기 위해 많은 양의 코드가 필요한 경우에 유용하다.
OS로부터 특별한 자원이 필요하지 않고, 프로그램 설계를 통해 구현된다. OS는 동적 로딩을 구현하기 위한 라이브러리를 제공한다.
Dynamic Linking
정적 링킹 : 시스템 라이브러리와 프로그램 코드가 로더에 의해 이진 프로그램 이미지로 결합된다.
동적 링킹 : 링킹이 실행 시간까지 연기된다.
작은 코드 조각인 스텁은 메모리에 상주하는 적절한 라이브러리 루틴을 찾는 데 사용된다.
스텁은 자신을 루틴의 주소로 대체하고 루틴을 실행한다. 운영체제는 해당 루틴이 프로세스의 메모리 주소에 있는지 확인한다. 만약 메모리 공간에 없다면 주소 공간에 추가한다.
동적 링킹은 라이브러리에 특히 유용하고, 시스템은 공유 라이브러리(shared libraries)로도 알려져 있다.
시스템 라이브러리의 패치에 대한 적용 가능성을 고려한다. 즉 버전 관리가 필요할 수도 있다.
dynamic loading과 달리 dynamic linking과 shared libraries는 OS의 도움이 필요하다.
Contiguous Allocation
메인 메모리는 운영체제와 상용자 프로세스를 모두 지원해야 한다.
메인 메모리는 제한된 자원이므로 효율적으로 할당돼야한다.
연속 할당은 초기 방법 중 하나이다.
메인 메모리는 일반적으로 두 개의 파티션으로 나뉜다.
- 상주 운영 체제는 보통 인터럽트 벡터와 함께 하위 메모리에 저장된다.
- 사용자 프로세스는 상위 메모리에 저장된다.
- 각 프로세스는 메모리의 단일 연속된 영역에 포함된다.
Variable Partition
다중 프로그래밍은 파티션의 수에 의해 제한된다.
효율성을 위해 가변적인 파티션 크기를 사용한다. (주어진 프로세스의 요구에 맞게 크기가 조정된다)
홀(hole)은 사용 가능한 메모리 블록을 의미하며, 다양한 크기의 홀이 메모리 공간 전체에 흩어져 있다.
프로세스가 도착하면 충분히 큰 홀로부터 메모리가 할당된다.
프로세스가 종료되면 해당 파티션이 해제되고 인접한 빈 파티션이 합쳐진다.
운영체제는 할당된 파티션과 빈 파티션(hole)에 대한 정보를 유지한다.
first fit : 충분히 큰 첫 번째 홀을 할당
best fit : 충분히 큰 가장 작은 홀을 할당
worst fit : 가장 큰 홀을 할당
first fit이 일반적으로 가장 빠르고, best fit은 저장 공간 활용 측면에서 우수하다.
Fragmentation
외부 조각(external fragmentation) : 사용중인 페이지 사이에 있어서 할당되지 못하는 메모리
내부 조각(internal fragmentation) : 페이지 내부에서 사용하지 않는 메모리
50% 법칙 : First-fit은 N개의 블록이 할당되었다면 0.5N개의 블록이 조각나서 사용할 수 없다. 이렇게 되면 전체에서 0.5N/(N+0.5N) = 1/3을 못쓰게 된다.
외부 조각을 줄이기 위해 압축(compaction)을 사용한다.
메모리 내용을 섞어서 모든 빈 메모리를 하나의 큰 블록으로 모아둔다.
압축은 재배치가 동적이고 실행 시간에 수행되는 경우에만 가능하다. - 조각모음은 실행중인 코드를 옮길 수 있어야 가능하다.
I/O 문제
- I/O에 참여하는 동안 작업을 메모리에 유지한다.
- I/O는 운영체제 버퍼로만 수행한다.
이제 백업 저장소도 같은 조각 문제를 고려해야 한다. - 저장공간은 fragmentation 문제를 가지고 있다.
Paging
물리적 메모리를 동일한 크기의 블록인 프레임으로 분할하고 가상 메모리를 이와 동일한 크기의 블록인 페이지로 나눈다.
프로세스의 물리적 메모리 공간은 불연속적일 수 있다. 즉 프로세스는 필요할 때마다 물리적 메모리를 할당받는다. 이로 인해 외부 조각을 피하고 다양한 크기의 메모리 조각 문제를 해결할 수 있다.
CPU에서 생성된 주소는 페이지 번호와 페이지 오프셋으로 나뉜다.
페이지 번호는 페이지 테이블의 인덱스로 사용되고, 페이지 테이블에는 각 페이지의 물리적 메모리 기본 주소가 들어있다.
페이지 오프셋은 기본 주소와 결합하여 메모리 단위로 보낼 물리적 메모리 주소를 정의한다.
예를 들어서, 페이지 크기가 2048바이트이고 프로세스 크기가 72766바이트인 경우 35페이지와 추가 1086바이트가 필요하다. 이 경우 내부 조각으로 인해 2048-1086=962 바이트가 낭비될 수 있다.
프레임의 크기가 작을 수록 좋게 보일 수도 있지만, 각 페이지 테이블 엔트리는 추적하기 위한 메모리를 사용한다.
페이지 크기는 증가하는 추세로, 가장 인기 있는 크기는 4KB와 8KB이다.
페이지 테이블은 메인 메모리에 유지되며, 페이지 테이블 기본 레지스터(PTBR)는 페이지 테이블을 가리키고, 페이지 테이블 길이 레지스터(PTLR)는 페이지 테이블의 크기를 나타낸다.
여기서 모든 데이터/명령어 접근이 두 번의 메모리 접근을 필요로 한다. 한 번은 페이지 테이블에 대한 접근, 한 번은 데이터/명령어에 대한 접근이다.
이 두 번의 메모리 접근 문제(two memory access problem)는 TLB(Translation Look-aside Buffer)라 불리는 빠른 검색 하드웨어 캐시를 사용함으로써 해결할 수 있다. TLB는 페이지 테이블에서 필요한 정보를 빠르게 찾아준다.
일부 TLB는 각 TLB 항목에 주소 공간 식별자를 저장해서 각 프로세스를 고유하게 식별하고 해당 프로세스에 대한 주소 공간 보호를 제공한다. TLB는 일반적으로 64~1024 항목으로 작고 TLB 미스가 발생하면 다음 번 빠른 접근을 위해 값이 TLB에 로드된다. 이 경우 교체 정책이 고려돼야하고, 일부 항목은 항상 빠르게 접근할 수 있도록 고정될 수 있다.
어떤 CPU는 instruction TLB와 data TLB를 별도로 제공하고, 계층구조를 가지기도 한다.
TLB lookup은 instruction pipeline의 일부이기 때문에 성능 손실이 전혀 없다.
TLB의 히트 비율(hit radio)은 페이지 번호가 TLB에서 찾아지는 비율을 의미한다.
메모리 접근 시간이 10나노초라고 가정할 때, 원하는 페이지를 TLB에서 찾았다면 매핑된 메모리 접근 시간이 10나노초가 걸린다. 만약 원하는 페이지를 찾지 못했다면 두 번의 메모리 접근이 필요하므로 20나노초가 걸린다.
만약 위 상황에서 hit radio가 80%라면,
EAT(Effective Access Time) = 0.8 * 10 + 0.2 * 20 = 12(ns)
가 된다.
Memory Protection
메모리 보호는 각 프레임에 보호 비트를 연결하여 읽기 전용인지 읽기-쓰기 접근이 허용되는지를 표시함으로 구현된다. 페이지가 실행 전용인지 등을 나타내는 더 많은 비트를 추가할 수도 있다.
valid-invalid 비트는 페이지 테이블의 각 항목에 첨부된다.
valid는 연관된 페이지가 프로세스의 논리적 주소 공간에 있으며, 따라서 합법적인 페이지라는 것을 나타낸다.
invalid는 페이지가 프로세스의 논리적 주소 공간에 없다는 것을 나타낸다.
또는 페이지 테이블 길이 레지스터(PTLR)를 사용할 수 있다.
위반하는 경우 모두 커널에 대한 트랩이 발생한다.
'학교강의필기장 > 운영체제론' 카테고리의 다른 글
운영체제론[16]: 가상메모리 - 1 (0) | 2023.06.22 |
---|---|
운영체제론[15]: 메모리 - 2 (0) | 2023.06.22 |
운영체제론[13]: 데드락 (0) | 2023.06.22 |
운영체제론[12]: 동기화 방법 (0) | 2023.06.22 |
운영체제론[11]: 스레드 동기화 (하드웨어 명령어) (0) | 2023.06.22 |