[CS Study] OS - Address binding

Frye 'de Bacon·2023년 11월 26일
0

Computer Science(CS)

목록 보기
22/40

논리적 주소와 물리적 주소

논리적 주소(Logical address)

프로그램이 실행을 위해 메모리에 적재되면(즉, 프로세스가 되면) 해당 프로세스를 위한 독자적인 주소 공간이 생성된다. 이를 논리적 주소 또는 가상 주소(Virtual address)라 하며, 각 프로세스마다 0번부터 주소가 시작된다. 그리고 CPU는 이 논리적 주소에 근거하여 명령을 실행한다.

물리적 주소(Physical address)

반면 물리적 주소는 실제 물리적 메모리에 프로세스가 적재되는 영역을 말한다. 물리적 메모리의 낮은 주소 영역에는 OS의 데이터가 적재되고, 높은 주소 영역에 사용자의 프로세스들이 적재된다.

기호 주소(Symbolic address)
변수나 함수와 같이 코드에서 사용하는 상징적인 주소로, 프로그래머의 입장에서 사용하는 주소이다. 단순하게는 변수명 혹은 함수명으로 이해하면 될 것이다.


주소 바인딩

CPU가 명령을 수행하기 위해서는 논리적 주소를 통해 메모리를 참조하며, 따라서 논리적 주소와 물리적 주소가 서로 매핑되어 있어야 한다. 이때 논리적 주소를 물리적 주소로 연결하는 작업을 주소 바인딩이라고 한다.

즉, 주소 바인딩은 symbolic address를 logical address를 거쳐 physical address와 연결하는 과정이라고 이해할 수도 있을 것이다.

주소 바인딩은 바인딩이 이루어지는 시기가 언제냐에 따라 세 가지로 분류할 수 있다.

컴파일 시간 바인딩(Compile time binding)

  • 컴파일 시 물리적 주소가 결정되는 방식
  • 컴파일 시에 주소 바인딩이 이루어져야 하므로 논리적 주소를 그대로 물리적 주소와 연결해야 한다(즉, 논리적 주소를 그대로 물리적 주소로 변환하므로 두 주소가 동일하다).
  • 물리적 주소 공간이 비어 있어도 항상 0번부터 주소를 연결하므로(논리적 주소는 각 프로세스마다 0번부터 시작하므로) 매우 비효율적
  • 물리적 주소를 변환하고 싶다면 컴파일을 다시 해야 한다.
  • 하나의 CPU에서 하나의 프로그램만 실행시키던 시기에만 사용했으며, 멀티 프로세싱이 일반화된 현대 OS 환경에서는 사용되지 않는 방법

적재 시간 바인딩(Load time binding)

  • 프로그램이 시작되어 메모리에 올라갈 때 물리적 주소가 결정되는 방식
  • 컴파일 시에는 논리적 주소만 결정됨

    예컨대 프로그램 시작 시 물리적 주소가 500번지부터 비어 있다면 논리적 주소 0번지를 물리적 주소 500번지와 매핑한다.

  • 로더(loader, 사용자 프로그램을 메모리에 적재시키는 프로그램)가 물리적 메모리 주소를 부여하며, 프로세스의 종료 시까지 물리적 주소가 고정됨
  • 메모리를 참조하는 명령어를 모두 변경해야 하므로 로딩 시간이 길어지며, 따라서 실제로는 사용되지 않는 방식

실행 시간 바인딩(Execution time binding)

  • 프로세스의 실행 도중 물리적 주소가 변경될 수 있는 방식
  • CPU가 주소를 참조할 때마다 해당 데이터가 물리적 메모리의 어느 위치에 존재하는지 주소 매핑 테이블을 이용해 주소 바인딩을 점검함
  • 다른 방식과 달리 프로세스의 실행 도중 바인딩이 이루어지므로 기준 레지스터한계 레지스터를 포함하여 MMU라는 하드웨어적 지원이 필요
    • 기준 레지스터(Base register) : 프로세스의 물리적 메모리의 시작 주소를 보유함
    • 한계 레지스터(Limit register) : 현재 CPU에서 수행 중인 프로세스의 논리적 주소의 최댓값, 즉 프로세스의 크기를 보유함
    • MMU(Memory Management Unit) : 논리적 주소를 물리적 주소로 매핑해주는 하드웨어

MMU(Memory Management Unit)의 동작 방식

CPU가 주소를 참조할 경우 MMU는 기준 레지스터의 값에 논리적 주소를 더하여 물리적 주소를 얻는다. 예를 들어 CPU가 논리적 주소 300에 있는 데이터를 요청하였고 기준 레지스터에 저장된 메모리 시작 주소가 2000이라면 MMU는 이 둘을 더하여 물리적 주소 2300에 있는 데이터를 로드하는 것이다.

그런데 논리적 주소값은 프로세스마다 독립적으로 할당되므로 프로세스 A와 프로세스 B에 각각 100번 논리적 주소가 있을 수 있다. 그러나 실제 각 프로세스의 100번 논리적 주소에 매핑되는 물리적 주소는 다를 것이다. 따라서 MMU는 문맥 교환(Context switching)이 일어날 때마다 기준 레지스터의 값도 함께 변경하는 재설정 작업을 진행한다.

한편 프로세스 A의 작업 중 CPU가 요청한 '논리적 주소값 + 기준 레지스터의 값'의 결과가 해당 프로세스의 주소 공간을 넘어 프로세스 B의 영역에 해당되는 경우가 발생할 수도 있다. 이 경우 메모리 보안이 이루어지지 않아 시스템에 문제가 발생할 수 있다. 따라서 이를 방지하기 위해 한계 레지스터를 사용, CPU가 논리적 주소를 요청할 때마다 한계 레지스터에 저장된 '최대 논리적 주소값'과 비교하여 그보다 작은지를 확인하고, 만약 그 범위를 벗어날 경우 트랩을 발생시켜 해당 프로세스를 종료시킨다.


메모리 관리(Memory management)

앞서 주소 매핑 방식을 설명할 때 전제했던 것은 프로그램의 실행 시, 즉 프로그램이 메모리에 적재되어 프로세스가 될 때 해당 프로그램 전체가 메모리에 적재된다는 것이다. 그런데 이 경우 프로세스의 크기가 메모리의 크기보다 클 수 없다는 한계가 생기며, 이것이 충족되더라도 메모리를 효율적으로 사용하지는 못한다는 단점이 발생한다.

OS는 메모리를 효율적으로 관리하기 위해 여러 가지 메모리 낭비 방지 기술들을 사용하며, 대표적인 방법으로 3가지를 들 수 있다.

동적 적재(Dynamic loading)

  • 프로그램의 실행에 반드시 필요한 루틴 및 데이터만 적재하는 것
  • 오류 처리와 같이 필요할 때만 사용하는 루틴, 배열과 같이 필요할 때만 사용되는 데이터처럼 프로그램의 실행에 필수적인 데이터가 아닌 것들은 해당 데이터가 '필요할 때' 메모리에 적재함
  • 메모리 이용의 효율성을 향상시킬 수 있음
  • OS의 특별한 지원 없이도 프로그램 자체에서 구현이 가능
  • 하나의 라이브러리 루틴만을 메모리에 저장하고, 다른 프로세스에서 해당 루틴을 실행할 경우 이 루틴과 연결하는 방식

    프로그램 A와 프로그램 B가 공통으로 print() 함수를 사용한다고 했을 때, 프로그램 전체를 메모리에 올리는 것은 메모리 낭비이다. 서로 중복되는 라이브러리 루틴인 print()는 하나만 적재하고, 프로그램 B가 해당 함수를 요청할 때 적재된 루틴과 연결하는 것이 효율적일 것이다.

  • 이처럼 동적으로 연결되는 공통 라이브러리 루틴을 리눅스에서는 공유 라이브러리(Shared library), 윈도우에서는 동적 연결 라이브러리(Dynamic Linking Library, DLL)라고 부른다.

스와핑(Swaping)

  • 메모리에 적재되어 있으나 현재 사용되지 않는 프로세스를 일시적으로 스왑 영역(Swap area)으로 보내었다가 실행 시 다시 메모리로 로드하는 방법
  • 스왑 영역을 Backing store 혹은 Swap device라고도 한다.
  • 일반적으로 스왑 영역은 HDD나 SSD와 같은 보조기억장치에 존재하나, 일반적으로 사용하는 보조기억장치 공간이 아니라 그 일부를 할당하여 별도로 만들어낸 공간이다.
  • 스왑 영역으로 프로세스를 내보내는 것을 스왑 아웃(Swap-out), 다시 메로리로 불러오는 것을 스왑 인(Swap-in)이라고 한다.

참고 자료

profile
AI, NLP, Data analysis로 나아가고자 하는 개발자 지망생

0개의 댓글