[OS] 물리 메모리 관리

Suyeon·2022년 2월 25일
0

Operating System

목록 보기
10/10

💡 시분할 시스템에서는 운영체제를 포함한 모든 응용 프로그램이 메모리에 올라와 실행되기 때문에 메모리 관리가 복잡하다. 이러한 메모리 관리는 메모리 관리 시스템(Memory Management System)이 담당한다.

1.1 관련 용어

  1. 메모리 주소 레지스터
    1. CPU는 메모리에 있는 내용을 가져오거나 작업 결과를 메모리에 저장하기 위해 메모리 주소 레지스터를 사용한다.
    2. 메모리 주소 레지스터에 메모리 주소를 넣으면 데이터를 메모리에 가져오거나 메모리에 데이터를 옮길 수 있다.
  2. 메모리 관리 이중성
    1. 프로세스 입장에서는 메모리를 독차지 하려고 하고, 메모리 관리자 입장에서는 관리를 효율적으로 하려고 하는 것
  3. 계층적 메모리 구조
    1. 메모리를 계층적 구조로 만들어 작업 속도를 올리고 가격을 낮추는 방법
    2. 느리고 값싼 하드디스크는 제 2저장장치로 사용하고 비싸고 빠른 메모리는 작업공간으로 사용
    3. 제2저장 장치 <—> 메모리<—> 캐시

1.2 컴파일러와 인터프리터

💡 언어 번역 프로그램은 고급언어로 작성한 소스코드를 컴퓨터가 실행할 수 있는 기계어로 번역하는 프로그램이다. 대표적인 언어 번역 프로그램은 컴파일러와 인터프리터가 있다.

1.2.1 컴파일러(Compiler)

  • 소스코드를 컴퓨터가 실행할 수 있는 기계어로 번역한 후 한꺼번에 실행한다.
  • 윈도우에서 프로그램의 exe 확장자는, 컴파일러가 번역한 기계어 코드의 확장자가 exe 라는 뜻이다.
  • 크고 복잡한 프로그램에 주로 사용
  • e.g. C언어, 자바등

동작 순서

  1. 사용할 변수를 먼저 선언한 후 코드를 작성한다.
    1. 변수선언은 오류를 찾고 코드를 최적화한다.
    2. 최적화 및 오류를 찾기 위해 심벌 테이블(Symbol table)을 사용한다.
      1. 심벌 테이블: 변수 선언부에 명시한 각 변수의 이름과 종류를 모아놓은 테이블
  2. 실행전에 소스코드를 점검하여 오류를 수정하고 필요없는 부분을 정리하여 최적화된 실행파일을 만든다.

컴파일 과정

💡 컴파일은 사용자가 작성한 소스코드를 목적 코드(Object Code)로 변환 후 라이브러리를 연결하고 최종 실행 파일을 만들어 실행하는 과정이다.

  1. 프로그래머가 작성한 소스코드를 컴파일하여 목적코드로 만든다.
  2. 라이브러리에 있는 코드를 목적 코드에 삽입하여 최종 실행 파일을 만든다.
  3. 동적 라이브러리를 포함해서 최종적으로 실행한다.
    1. printf() 의 자리를 비워놓고 컴파일한 후 실행할 때 printf()의 실행코드를 라이브러리에서 가져와 실행한다.
    2. 동적 라이브러리 방식에서는 함수가 변경되어도 새로 컴파일할 필요가 없다.
    3. 윈도우에서는 동적라이브러리 파일을 DLL(Dynamic Link Loader)라고 부른다.

1.2.2 인터프리터(Interpreter)

  • 소스코드를 한 행씩 번역하여 실행한다.
  • 한줄씩 위에서부터 아래로 실행되기 때문에 같은 일을 반복하는 경우나 필요없는 변수를 확인할 수 없다.
  • 간단한 프로그램에 사용
  • e.g. 자바스크립트

1.3 메모리 관리자의 역할

💡 메모리 관리는 메모리 관리자가 담당한다. 메모리 관리자는 메모리 관리 유닛(Memory Management Unit, MML)이라는 하드웨어인데 일반적으로 메모리 관리자라고 일컫는다. 메모리 관리자의 작업은 가져오기(fetch), 배치(placement), 재배치(replacement)이다.

  1. 배치 작업
    1. 가져온 프로세스와 데이터를 메모리의 어떤 부분에 올려놓을지 결정하는 작업
    2. 배치 작업전에 메모리를 어떤 크기로 자를 것인지가 매우 중요하다.
      1. 자르는 기준에 따라 메모리 관리의 복잡성이 달라지기 때문이다.
  2. 배치 정책
    1. 가져온 프로세스를 메모리의 어떤 위치에 올려놓을지 결정하는 정책
      1. 페이징(Paging): 메모리를 같은 크기로 자르는 것
      2. 세그먼테이션(Segmentation): 프로세스의 크기에 맞게 자르는 것
  3. 재배치 정책
    1. 메모리가 꽉 찼을 때 메모리 내에 있는 어떤 프로세스를 내보낼지 결정하는 정책
    2. 교체 알고리즘(Replacement Altorithm): 앞으로 사용하지 않을 프로세스를 찾아서 내보내는 알고리즘

1.4 메모리 주소(Memory Address)

💡 메모리에 접근할 때는 메모리 주소를 이용한다. 메모리는 운영체제 영역과 사용자 영역으로 나누어 관리된다. 운영체제는 시스템을 관리하는 중요한 역할을 하기 때문에 사용자가 운영체제를 침범하지 못하도록 분리하여 관리한다.

1.4.1 CPU Bit

  • CPU의 비트는 한번에 다룰 수 있는 데이터의 최대 크기를 의미한다.
    • 32bit CPU는 한번에 다룰 수 있는 데이터의 최대 크기가 32bit이다.
    • 32bit 내의 레지스터 크기, 산술 논리 연산 장치, 데이터를 전송하는 각종 버스의 크기, 대역폭등 CPU 내부 부품은 모두 이 비트를 기준으로 제작된다.
  • CPU의 비트는 메모리 주소 공간(Address Space)의 크기와도 연관이 있다.

1.4.2 경계 레지스터

  • 사용자 영역이 운영체제 영역으로 침범하는 것을 막는 하드웨어이다.
  • 운영체제 영역과 사용자 영역 경계 지점의 주소를 가진 레지스터이다.
  • 메모리 관리자는 사용자가 작업을 요청할 때마다 경계 레지스터의 값을 벗어나는지 검사하고, 만약 경계 레지스터를 벗어나는 작업을 요청하는 프로세스가 있으면 그 프로세스를 종료한다.

1.4.2 절대 주소와 상대 주소

💡 메모리의 주소 공간을 물리 주소 공간(physical address space)논리 주소 공간(logical address space)로 나눌 수 있다.

  1. 메모리 접근시 절대 주소를 사용하면 특별한 변환 과정 없이 작업할 수 있다.
  2. 메모리 접근시 상대 주소를 사용하면 실제 메모리 내의 물리 주소, 즉 절대 주소로 변환해야한다.
    1. 메모리 관리자는 사용자 프로세스가 상대 주소를 사용하여 메모리에 접근할 때마다, 상대 주소값이 재배치 레지스터 값을 더하여 절대 주소를 구한다.
    2. 재배치 레지스터: 주소 변환의 기본이 되는 주소값을 가진 레지스터
    3. 메모리에서 사용자 영역의 시작 주소값이 저장된다.
    4. e.g. 운영체제 영역이 바뀌어 사용자 영역이 500번지 부터 시작한다면 재배치 레지스터에 500을 넣으면 된다.
구분절대 주소상대주소
관점메모리 관리자 입장사용자 프로세스 입장
주소 시작물리 주소 0번지 부터 시작물리 주소와 관계없이 항상 0번지부터 시작
주소 공간물리 주소 공간 (메모리 주소 레지스터가 실제로 사용하는 주소)논리 주소 공간

1.5 단일 프로그래밍 환경에서의 메모리 할당

💡 단일 프로그래밍에서는 메모리 오버레이와 스왑을 사용하여 메모리를 효율적으로 관리한다. (과거 일괄 프로그래밍)

1.5.1 메모리 오버레이(Memory Overlay)

  • 프로그램의 크기가 실제 메모리(물리 메모리)보다 클 때 전체 프로그램을 메모리에 가져오는 대신 적당한 크기로 잘라서 가져오는 기법
  • 프로그램을 몇개의 모듈로 나누고 필요할 때마다 모듈을 메모리에 가져와서 사용한다.
    • 어떤 모듈을 가져오거나 내보낼지는 CPU 레지스터중 하나인 프로그램 카운터(PC)가 결정한다.
    • 프로그램 카운터: 앞으로 실행할 명령어의 위치를 가리키는 레지스터로, 해당 모듈이 없으면 메모리 관리자에게 요청하여 메모리로 가져오게 한다.
  • 프로그램 전체가 아니라 일부만 메모리에 올라와도 실행이 가능하다.
  • 프로그램 전체를 메모리에 올려놓고 실행하는 것보다 속도가 느리지만 메모리가 프로그램보다 작을 때도 실행 할 수 있어서 유용하다.

1.5.2 스왑(Swap)

  • 메모리가 모자라서 쫓겨난 프로세스가 임시로 저장되는 저장장치의 영역
  • 스왑 영역은 메모리 관리자가 관리한다.
    • 하드디스크같은 저장장치는 저장장치 관리자가 관리한다.
    • 스왑영역은 메모리에서 쫓겨났다가 다시 돌아가는 데이터가 머무는 곳이기 때문에 저장장치는 장소만 빌려주고 메모리 관리자가 관리한다.
  • 사용자는 실제 메모리의 크기와 스왑 영역의 크기를 합쳐서 전체 메모리로 인식하고 사용할 수 있다.
    • 실제 메모리 1GB, 스왑의 크기 3GB = 사용자가 인식하는 메모리는 4GB
  • 최대 절전 모드 사용은 대표적인 스왑 영역의 예시이다.
    • CPU와 메모리의 전력 공급이 끊기기 때문에 메모리의 모든 내용이 사라진다.
    • 원래 작업으로 복귀시키려면 현재 메모리에 있는 데이터를 어딘가에 옮겨야하는데 이 때 스왑영역을 사용한다.

1.6 다중 프로그래밍 환경에서의 메모리 할당

💡 한번에 여러 프로세스를 동시에 실행하는 경우 메모리 관리가 복잡해지는데 프로세스들의 크기가 달라 메모리를 어떻게 나누어 사용할지 고민이 필요하다. 메모리를 어떤 크기로 나눌것인가는 메모리 배치 정책에 해당된다.

메모리 배치 정책은, 아래와 같이 나뉜다.

  1. 가변 분할 방식
  2. 고정 분할 방식
구분가변 분할 방식고정 분할 방식
메모리 단위세그멘테이션페이징
특징연속 메모리 할당비연속 메모리 할당
장점프로세스를 한덩어리로 관리 가능메모리 관리가 편리
단점빈공간의 관리가 어려움프로세스가 분할되어 처리됨
단편화외부 단편화내부 단편화

1.6.1 가변 분할 방식

  • 프로세스의 크기에 맞게 메모리가 분할되므로 메모리의 영역이 각각 다르다.
  • 세그멘테이션 기법(Segmentation)
  • 연속 메모리 할당(Contiguous Memory Allocation)
    • 한 프로세스가 연속된 공간에 배치된다.
  • 메모리 관리가 복잡하다.
    • 외부 단편화로 인해 부가적인 작업이 필요하다. (메모리 배치 방식, 조각 모음)
  • 빈 영역이 있어도 서로 떨어져있으면 프로세스를 배정받지 못한다.
    • 이로 인해 작은 조각들이 발생하는 현상을 단편화(Fragmentation) 또는 조각화라고 한다.
  • 17KB의 빈공간이 생긴 경우, 17KB보다 큰 프로세스가 들어오면 적당한 공간이 없어 메모리를 배정받지 못한다.
    • 이러한 빈공간을 외부 단편화(External fragmentaion)이라고 한다.
    • 외부 단편화로 인한 문제를 해결하기 위해 메모리 배치 방식(Memory Placement Strategy)이나 조각 모음(Defragmentation)을 사용한다.

1.6.1.1 메모리 배치 방식

💡 작은 조각이 발생하지 않도록 프로세스를 배치하는 것 — 선처리
최초, 최적, 최악 배치를 사용해도 단편화 현상이 발생한다.

  1. 최초 배치

    1. 메모리에서 적재 가능한 공간을 순서대로 찾다가 첫번째로 발견한 공간에 프로세스를 배치
  2. 최적 배치

    1. 메모리의 빈공간을 모두 확인한 뒤 적당한 크기 가운데 가장 작은 공간에 프로세스를 배치
    2. 빈 공간을 모두 확인하는 부가적인 작업이 있지만 딱 맞는 공간을 찾을 경우 단편화가 일어나지 않는다. 그렇지 않은 경우에는 조각을 만든다.
  3. 최악 배치

  4. 빈공간을 모두 확인한 뒤 가장 큰 공간에 프로세스를 배치

  5. 빈 공간의 크기가 클 때는 효과적이지만 빈 공간의 크기가 점점 줄어들면 최적 배치처럼 조각을 만든다.

1.6.1.2 조각 모음

💡 조각이 발생했을 때 작은 조각들을 모아서 하나의 큰 덩어리로 만드는 작업 — 후처리
아래의 작업을 해야하기 때문에 많은 시간이 걸린다.

  1. 조각 모음을 하기 위해 이동할 프로세스의 동작을 멈춘다.
  2. 프로세스를 적당한 위치로 이동한다.
  3. 다시 프로세스를 시작한다.

1.6.1.3 버디 시스템

  • 가변 분할 방식의 단점인 외부 단편화를 완화하는 방법
  • 가변 분할 방식과 고정 분할 방식의 중간 구조
    • 가변 분할 방식처럼 메모리가 프로세스 크기대로 나뉜다.
    • 고정 분할 방식처럼 하나의 구역에 다른 프로세스가 들어갈 수 없고 메모리 한 구역의 내부에 조각이 생겨 내부 단편화가 발생한다.
  • 비슷한 크기의 덩어리가 서로 모여있어서 통합하기가 쉬워 가변 분할 방식보다 효과적으로 공간을 관리할 수 있다.

동작 순서

  1. 프로세스의 크기에 맞게 메모리를 1/2로 자르고 프로세스를 메모리에 배치한다.
  2. 나뉜 메모리의 각 구역에는 프로세스가 1개만 들어간다.
  3. 프로세스가 종료되면 주변의 빈 조각과 함쳐서 하나의 큰 덩어리를 만든다.

1.6.2 고정 분할 방식

  • 프로세스의 크기에 상관없이 메모리가 같은 크기로 나뉘며, 큰 프로세스가 메모리에 올라오면 여러 조각으로 나뉘어 배치된다.
  • 페이징 기법(Paging)
  • 비연속 메모리 할당(Noncontiguous Memory Allocation)
    • 한 프로세스가 분산되어 배치된다.
  • 메모리 관리가 쉽다.
    • 메모리에 남은 공간이 없는 경우 프로세스는 스왑영역으로 옮겨진다.
  • 일정하게 나뉜 공간보다 작은 프로세스가 올라올 경우 메모리 낭비가 발생한다.
    • 내부 단편화(Internal fragmentaion): 각 메모리 조각에 프로세스를 배치하고 공간이 남는 현상
    • 동일하게 분할되는 공간의 크기를 조절하여 내부 단편화를 최소화한다.

💡 현대 운영체제에서 메모리 관리는 기본적으로 고정 분할 방식을 사용하면서 일부분은 가변 분할 방식을 혼합하고 있다.

profile
Hello World.

0개의 댓글