Background
- 프로그램은 실행되기 위해서 디스크로부터 메모리로 load 되어야 함
- 메인 메모리와 레지스터는 CPU가 직접 접근할 수 있는 유일한 저장 장치
- 레지스터는 CPU 내부의 저장 장치이고 메인 메모리는 CPU와는 구분되는 별도로 위치하는 저장 장치
- 메인 메모리는 주소가 붙은 일련의 바이트들의 집합
- 레지스터는 CPU 관점에서 봤을 때 보통 한 clock(CPU 동작의 기준이 되는 clock) 이내에 매우 빠르게 접근 가능
- 메인 메모리의 접근은 수 clock 사이클이 소요됨
- 메인 메모리 접근 속도 한계를 극복하기 위헤 메인 메모리와 레지스터 중간에 캐시 메모리를 사용
Base and Limit Registers

- CPU가 메인 메모리를 접근할 때는 허용된 범위 내에서 접근하게 하는 것이 매우 중요
- 사용자 프로세스는 kernel의 메모리 영역을 접근하면 안됨
- 한 프로세스는 다른 프로세스가 사용 중인 영역을 접근해서도 안됨
- base and limit register
- protection을 보장하기 위해 CPU에 존재하는 레지스터로, 현재 접근할 수 있는 메모리 영역을 정의
- CPU는 메모리 접근 시 접근 주소가 이 두 레지스터가 정의하는 범위 내에 있는지 검사
Hardware Address Protection

- base 레지스터와 limit 레지스터를 통한 메모리 protection이 실제로 적용되는 과정
- 이 과정은 소프트웨어적으로 프로그래밍 된 동작이 아닌 모든 메모리 접근마다(CPU가 주소를 만들 때마다) 하드웨어적으로 이루어지는 동작
- 불법적인 메모리 접근이 발생하면 trap이 발생하고 이를 OS가 처리
- 보통 해당 프로세스를 강제 종료하는 방식으로 처리가 이루어짐
Address Binding
- 프로그램이 프로그램 안에서 사용하는 상대적인 주소를 실제 메인 메모리 상의 물리주소로 연관시키는 것
- 프로그래밍을 할 때 사용하는 주소는 최종적으로 실행할 때의 최종 주소와 다름
- 프로그램이 사용하는 주소의 최종 값은 binding이 이루어지는 시점에 따라서 결정됨
- Compile time
- 컴파일을 해서 만들어지는 object 파일 내에서 사용되는 주소가 최종 실행 시의 물리주소와 같은 경우
- 프로그래머가 자신의 프로그램 내의 최종 주소를 직접 결정하고 프로그래밍을 하는 경우
- 이렇게 만들어진 프로그램은 실행 시에 늘 동일한 물리 메모리 위치에서만 실행
- Load time
- 컴파일 시에 최종 주소가 확정되는 것이 아니고 상대적인 주소를 사용하는 코드가 만들어지게 됨
- 매번 실행될 때마다 각기 다른 물리주소에서 실행을 시작
- Execution time (runtime)
- 한 번 결정된 주소가 실행 중에 바뀔 수도 있음
Logical vs Physical Address Space
- 논리주소 공간을 물리주소 공간에 연결시키는 기법이 메모리 관리의 핵심
- Logical address (논리주소, 가상주소) : CPU가 메모리를 접근할 때 만들어내는 주소
- Physical address (물리주소) : 메모리 입장에서 보는 주소
- compile time에 binding하는 시스템과 load time에 binding하는 시스템에서는 논리주소와 물리주소 값이 동일함
→ CPU가 만들어내는 논리주소가 바로 해당 물리주소
- execution time에 binding하는 시스템은 논리주소와 물리주소가 다름
→ 매번 접근 시마다 논리주소에서 물리주소로 변환이 이루어져야 함
- Logical address space (논리주소 공간) : 프로그램이 실행하면서 만들어낼 수 있는 가능한 모든 논리주소의 집합
- Physical address space (물리주소 공간) : 논리주소 값들이 물리주소로 변환됐을 때 가질 수 있는 모든 물리주소의 집합
Memory-Management Unit (MMU)

- CPU가 만들어내는 논리주소를 물리주소로 mapping하는 CPU 내의 하드웨어 장치
- 가장 간단한 변환 방식은 relocation register를 사용하는 것
- 프로그램 실행 중 만들어내는 모든 논리주소마다 relocation register의 값을 더해서 물리주소를 생성
- 응용 프로그램은 논리주소만을 다루며 물리주소는 알 필요가 없음
- 물리주소 변환은 하드웨어가 수행하며 프로그래머 입장에서는 논리주소만 신경쓰면 됨
Dynamic Linking and Shared Library
- Static linking
- 최종 프로그램에 사용한 library 함수가 포함되는 것
- 프로그램이 library 함수를 사용하게 되면 link하는 과정에서 내 프로그램과 library 함수가 합쳐져서 하나의 실행 파일이 만들어지게 됨
- static library : static linking에 사용되는 library
- Dynamic linking
- stub이라고 하는 아주 작은 코드를 library 함수 대신 프로그램에 포함시키는 방식
- 실행 파일의 크기가 static linking을 사용했을 때보다 작아짐
- shared library : dynamic linking에 사용되는 library
- library 함수 자체가 개별 프로그램에 복사되는 대신 시스템 전체적으로 미리 한 copy만 메모리에 올라감
- stub은 프로그램 실행 시 자기 자신을 미리 메모리에 올라가있는 library routine의 주소로 대체하는 동작을 함
- OS는 프로그램 실행 시 이 프로그램이 사용하는 shared library가 메모리에 load 되어 있는지를 확인한 뒤 없으면 메모리에 추가함
Swapping

- 메모리 관리 기법 중 하나
- degree of multiprogramming의 값이 메인 메모리 공간에 비해서 너무 큰 경우 일부 프로세스를 임시로 backing store라는 곳에 내보냈다가 나중에 메인 메모리 공간에 여유가 생기면 다시 불러들이는 기법
- degree of multiprogramming : 멀티프로그래밍에서 메인 메모리에 적재되어 있는 프로세스의 개수
- medium-term scheduler : swapping을 수행하는 스케줄러
- swapping을 하는 시스템에서는 전체 프로세스의 크기가 물리 메모리의 크기보다 클 수 있음
- Backing store로는 주로 하드디스크가 사용됨
- 하드디스크는 모든 프로세스 이미지를 수용할 수 있을 만큼 넉넉한 저장 공간을 가지기 때문
- 하드디스크를 읽거나 쓰는데 걸리는 시간이 비교적 짧기 때문
- swapping 동작 시간의 대부분은 디스크를 읽고 쓰는 transfer time이 차지
Context Switch Time including Swapping
- dispatcher가 다음 실행할 프로세스를 선택했는데 이 프로세스가 swap out 되어서 디스크에 머무르는 프로세스라고 가정
- 메인 메모리에 빈 공간이 없다면 현재 메모리에 올라온 프로세스 중 무언가를 내보내서 빈 공간을 마련한 후 원하는 프로세스를 불러들여야 함
→ swapping을 포함한 context switch에는 매우 긴 시간이 소요됨
- 사용자 프로세스 크기가 100MB이고 디스크 전송률을 초당 50MB라고 가정
- swap out : 2초
- swap in : 2초
- 전채 context switch에 4초라는 긴 시간이 걸리게 됨
- 사용자 프로세스에 의해 실제 사용되고 있는 메모리 크기를 정확히 파악하면 swapping에 걸리는 시간을 줄일 수 있음
- 사용자가 메모리 요구사항에 대한 변화가 있을 때마다 시스템에 알려줘야 함
→ 시스템콜 필요
Swapping (Cont.)
- swap out된 프로세스가 다시 swap in 될 때 원래의 메인 메모리 위치로 돌아와야 하는가?
- 시스템 binding 방법에 따라 달라지는데, 유연성을 고려하면 아무 위치로나 돌아올 수 있도록 하는 것이 바람직
→ 다만 이는 runtime binding에서만 가능
- 프로세스를 swapping 하려면 그 프로세스가 완전한 휴지 상태에 있음을 확인해야 함
- 예를 들어 입출력을 비동기적으로 수행 중인 프로세스는 swapping 대상이 되면 안됨
- 혹은 입출력을 프로세스로 직접 하지 말고 OS의 buffer와만 하도록 하는 방법 (double buffering)
- OS와 프로세스 사이 전송은 프로세스가 swap 되어 들어온 상태에서만 수행
- 사용자가 데이터를 접근하기 전 kernel 메모리로부터 user 메모리로 다시 한 번 복사해야 되므로 overhead가 발생할 수 있음
- 최근 OS에서는 기본적인 swapping은 거의 사용하지 않는 대신 변형된 버전의 swapping 사용
- 평상시에는 swapping이 동작하지 않도록 하다가 메인 메모리 빈 공간이 일정 수준 이하로 떨어지면 동작하는 방식
- 프로세스 전체를 swapping 하는 것이 아닌 일부만 대상으로 하여 디스크 입출력 시간을 줄이는 방식
Swapping on Mobile Systems
- 모바일 시스템은 보통 어떤 형태의 swapping도 지원하지 않음
- 모바일 장치에서는 영구 저장 장치로 디스크 대신 flash memory를 사용
→ 저장 공간이 작고 쓰기 횟수가 제한이 있는 특성 때문에 swapping을 하지 않음
- 대신 다른 방식으로 메모리 빈 공간을 확보
- iOS 같은 경우 메모리 빈 공간이 임계값보다 떨어지면 앱들에게 할당된 메모리를 자발적으로 반환하도록 요구
- 읽기 전용 데이터는 필요에 따라 시스템에서 제거되고 나중에 flash로부터 다시 load 됨
- 충분한 메모리를 반환하지 못한 경우 강제 종료 될 수 있음
- Android도 iOS와 유사한 방식으로 빈 메모리 공간을 확보
- 종료하기 전 앱의 상태를 flash 메모리에 저장해서 나중에 빠르게 재시작할 수 있도록 함
- iOS와 Android는 paging을 지원하므로 메모리 관리에 큰 문제가 없음
참고 자료 : Operating System Concepts Essentials
*이미지 자료는 교재 자료를 직접 다시 만든 것으로 무단 불펌 금지입니다
끗~