Computer Science/운영체제

운영체제 시리즈 10. Memory management -1

nauni 2021. 1. 8. 09:47

32비트 컴퓨터의 주소공간의 체계

헷갈려서 위의 그림이 정확히 맞는지는 모르겠다. 하지만 요지는 메모리는 주소를 통해 접근하는 저장장치이다. 이 때 효율적인 관리를 위해 페이지 단위로 나눠서 관리한다.

주소 바인딩

주소는 가상주소와 물리적 주소로 나눌 수 있다.

 

  • 가상주소(virtual address), 논리적 주소(logical address) : CPU에 의해 프로세스마다 독립적으로 만들어진 주소이다. CPU가 가상주소를 바라보고 MMU를 통한 주소변환으로 물리 메모리에 올려 그 주소의 데이터를 사용하게 된다.
    (가상주소의 개념이 이해하기 어려워 스왑영역과 헷갈려 하기도 했다. 가상주소는 말 그대로 CPU가 바라보는 주소이다. 스왑영역은 메모리 공간이 부족할 때 확장 개념으로 사용하는 별개의 개념이다. 스왑영역은 일반 디스크의 파일시스템과는 구분되며 디스크의 파일시스템은 비휘발성인데 비해 스왑영역은 휘발성 메모리의 특성을 가진다고 한다.)
  • 물리적 주소(physical address) : 물리적 메모리에 실제 올라가는 위치를 의미한다. CPU가 실행할 때 사용하는 메인메모리에서의 주소를 의미한다.

 

CPU가 명령을 수행하기 위해서 가상주소를 통해 메모리 참조를 하게되면 물리적 메모리의 어느 위치에 올라오는지 확인해야한다. 이렇게 가상주소의 값을 물리적 주소의 값과 연결시켜 주는 작업을 주소 바인딩(address binding)이라고 한다.

바인딩 시점에 따른 구분

소스코드에 있는 값들은 symbolic address에 위치하고 소스코드가 컴파일되면 실행파일의 logical address에 위치하게 된다. 이것이 실행되려면 물리적 주소와 바인딩 시켜주어야 하는 것이다.

 

  • Compile time binding : 물리적 메모리의 주소가 컴파일 할 때 결정된다. 컴파일 시점에 해당 프로그램이 물리적 메모리에 몇 번지에 위치할 것인지 정해지므로 절대코드(absolute code)를 생성하는 바인딩 방식이라고 하기도 한다. 위치를 변경하려면 재컴파일이 필요하다.
  • Load time binding : 물리적 메모리의 주소가 실행이 시작될 때결정된다. loader라는 사용자 프로그램을 메모리에 올리는 프로그램에 의해 물리적 메모리의 주소가 결정된다. 프로그램이 종료될 때까지 그 주소는 고정된다. 컴파일러가 재배치가능한 코드를 생성한 경우 가능하다.
  • Execution time binding (= Runtime binding) : 물리적 메모리의 주소가 프로그램이 실행된 이후에도 변경이 가능하다. CPU가 주소를 참조할 때마다 주소 매핑 테이블(address mapping table)을 통해 바인딩을 점검한다. 실행시간 바인딩이 가능하기 위해서는 MMU라는 하드웨어 적인 지원이 필요하다.

MMU(Memory Management Unit)

MMU는 메모리 관리 유닛으로 논리주소를 물리주소로 맵핑해주는 하드웨어 장치이다. 주소값에 기준레지스터 값을 더해 물리적 주소값을 알아낸다. 기준 레지스터(base register)재배치 레지스터(relocation register)라고도 하며, 프로세스의 물리 메모리 시작주소를 가지고 있다. MMU 에서는 프로그램의 주소가 물리적 메모리의 한 공간에 연속적으로 쌓인다고 가정한다. 메모리에 다른 영역에 접근하는 것을 막기 위한 보안의 개념으로 한계레지스터(limit register)를 사용한다. logical address가 한계값 이하인지를 확인하고 재배치 레지스터의 값을 더해 물리적 메모리의 주소 값을 알아낸다. 한계 레지스터 값을 넘어가는 요청이 올 경우 트랩을 발생시켜 해당 프로세스를 강제 종료 시킨다.

MMU 작동방식

여기서 내가 가졌던 의문은 저렇게 사용한다면 물리 메모리에 모든 프로세스가 올라가는 것과 다를 게 없지 않나? 였다. 그럼 virtual memory를 사용할 이유도 없을 텐데라고 생각했다. 하지만 프로세스가 바뀔 때, 물리메모리의 메모리 구성도 바뀌고 재배치 레지스터와 한계 레지스터의 값도 바뀐다고 생각하면 된다. MMU와 물리 메모리의 셋팅이 변경되기 때문에 이 방식이 의미있는 것이다.

메모리 관련 용어

Dynamic loading

프로세스의 주소영역을 전체를 올리는 것이 아니라 해당되는 부분이 호출될 때 메모리에 올리는 방식이다. 동적 로딩 기법은 많은 양의 코드가 메모리에 올라가는 것을 막아 좀 더 효율적인 메모리 사용이 가능하다. 예를 들면 예외처리 루틴이 있다. 이런 방어용 코드가 호출될 때만 메모리에 로드하는 것이다. 사용자가 구현가능하며 OS에서는 라이브러리를 통해 지원가능하다.

Overlays (Manual overlay)

프로세스의 주소공간을 분할하여 실제 필요한 부분만 적재하는 기법이다. 동적 로딩과 비슷하다고 느낄 수 있으나 목적이 다르다. 동적로딩은 메모리의 효율성을 위해 필요한 부분만 올리는 방식이라면, 중첩은 물리 메모리가 프로그램보다 작을 경우 분할하여 필요한 부분만 올리는 것이다. 초창기에 물리 메모리가 작을 때, 프로그램의 크기가 물리 메모리보다 작다면 전체를 올릴 수 있지만 아닌 경우, 분할하여 올리기 위해 만들어진 것이다. OS의 지원없이 사용자에 의해 구현된다.

Swapping

메모리에 올라온 프로세스의 주소공간 전체를 backing store(swap area)에 일시적으로 쫓아내는 것을 의미한다.

 

swapper라는 중기스케줄러에 의해 스왑아웃시킬 프로세스를 선정하며, 선택된 프로세스 전체는 스왑아웃 당한다. (중기스케줄러 정리내용)  스왑핑의 중요한 역할은 물리 메모리에 존재하는 프로세스의 수를 조절하는 것이다. 다중 프로그래밍의 정도(degree of multi-programming)를 조절할 수 있다. 컴파일 타임 바인딩과 로드 타임 바인딩 방식에서는 스왑아웃 후 다시 스왑인 될 때 기존의 메모리 위치로 다시 올라가야 한다. 하지만 실행시간 바인딩에서는 새롭게 주소를 할당받을 수 있다. 스와핑에 소요되는 시간은 디스크 섹터에서 실제 데이터를 읽고 쓰는 전송시간(transfer time)이 대부분을 차지한다. 

Dynaminc Linking

여러개의 컴파일 된 파일을 묶어(소스코드가 컴파일된 object file + 이미 컴파일 된 library file) 하나의 실행파일을 만드는 것을 연결(linking)이라고 한다. 동적연결은 linking을 실행시간까지 미루는 기법이다. 

 

반대 개념인 정적연결(static linking)을 살펴보겠다. 정적연결은 라이브러리가 소스코드와 모두 합쳐져서 실행파일이 생성된다. 실행파일의 크기가 크며, 하나의 라이브러리를 여러개의 프로세스가 사용한다면 프로세스마다 라이브러리를 개별적으로 메모리에 올려야하기 때문에 물리적 메모리가 낭비된다.

 

동적연결은 라이브러리가 실행시점에 연결된다. 실행파일에 포함되지 않으며, 프로그램이 실행되면서 라이브러리를 호출 할 때 연결되는 것이다. 호출 부분에 stub이라는 코드를 둔다. 라이브러리가 이미 물리메모리에 있다면 사용하고 아니면 동적연결을 통해 디스크에서 읽어오게 된다. 동일한 라이브러리가 다른 프로세스에서 사용되더라도 메모리에 한 번만 올리므로 메모리 사용 효율을 높일 수 있다. 동적연결 기법은 OS의 지원을 필요로 한다.

정리

메모리는 주소를 통해 접근하는 장치이다. 메모리 주소는 크게 가상주소와 물리 주소로 나뉜다. 가상메모리는 프로그램마다 독립적으로 가지는 메모리이며, 물리 메모리는 CPU가 프로세스를 수행할 때 참조하게 되는 메인메모리를 뜻한다. 가상 주소를 물리 주소로 연결시키는 과정을 바인딩이라고 한다. 실시간 바인딩 방식을 주로 사용한다.

 

1편에서는 메모리 주소와 물리적, 가상 메모리의 개념에 대해 정리하였다면 2편에서는 물리적 메모리의 할당방식에 대해 정리해보겠다.

 

메모리 관리 참고한 블로그

운영체제 시리즈는 반효경 교수님의 운영체제 강의 와 "운영체제와 정보기술의 원리"라는 책을 바탕으로 정리한 내용입니다.