## 목차 ##



## 1. 메모리 관리의 개요 ##

(1) 메모리 관리의 복잡성

  • 메모리의 '워드'란 메모리에 저장되는 데이터의 크기를 가리킨다.

    • 아래 그림은 메모리 워드가 1byte인 메모리 모습이다.
  • 메모리의 워드마다 주소(번지)가 붙는다.

memory_address

  • 메모리는 유일한 작업공간이다.

    • 모든 프로그램은 메모리에 올려야 실행이 가능하다.
  • 메모리 관리의 복잡성

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



(2) 메모리 관리의 이중성

  • 메모리 관리의 이중성

    • 프로세스는 메모리를 독차지하려하고 관리자는 메로리를 효율적으로 관리하고 싶어하는 문제
    • 프로세스 입장에서 작업의 편리함과 관리자 입장에서 관리의 편리함이 충돌
    • 둘의 상충되는 요구사항을 처리해야한다.
  • 한정된 메모리에서 여러 작업을 동시에 실행해야 하는 문제에서 비롯되었다.



(3) 소스코드의 번역과 실행

  • 언어 번역 프로그램

    • 고급 언어(C, Java 등)으로 작성한 소스코드를 컴퓨터가 실행할 수 있는 저급 언어(어셈블리어, 기계어)로 번역하는 프로그램이다.
    • 컴파일러(compiler), 인터프리터(interpreter)
  • 컴파일러

    • 소스 코드를 기계어로 번역 후 한꺼번에 실행한다.
    • C언어, Java 등
    • 오류를 발견하여 실행 시 문제가 없도록 한다.
    • 실행 전에 코드를 점검하여 오류를 수정하고 최적화함으로써 작고 빠른 실행 파일을 만든다.
  • 컴파일러의 목적

    • 오류 발견(오류를 찾기위해 심볼 테이블 사용)
    • 코드 최적화(미리 코드 전체를 보고 이를 최적화)
  • 인터프리터

    • 소스코드를 한 행씩 번역하여 실행한다.
    • 자바스크립트, 파이썬 등
    • 한 줄씩 실행되기 때문에 컴파일러처럼 실행 전 최적화가 불가능하다.
    • 컴파일러에 비해 비교적 소형이고 간단한 프로그램에 사용한다.
  • 컴파일 과정

    • 컴파일하여 목적코드 생성
    • 라이브러리를 연결하여 최종 실행파일 생성(링커)
    • 실행시에 실행 코드를 라이브러리에서 가져와 실행한다.(동적 라이브러리 로딩)

(4) 메모리 관리자의 역할

  • 메모리 관리를 하는 하드웨어 유닛

    • 가져오기(fetch)
    • 배치(placement)
    • 재배치(replacement)
  • 가져오기

    • 프로세스와 데이터를 메모리로 로드
    • 용량이 큰 데이터는 일부씩 여러번 가져와 실행
    • 필요할 것이라고 예상되는 데이터를 미리 로드하기도 한다.(선인출 prefetch)
    • 언제 메모리로 가져올지 결정하는 '가져오기 정책'을 따른다.
  • 배치

    • 프로세스나 데이터를 어느 위치에 넣을지 결정하는 작업
    • 메모리를 어떤 크기로 자를지가 매우 중요
    • 어떤 위치에 올릴지 결정하는 '배치 정책'을 따른다.
    • 메모리를 같은 크기로 자르는 고정 분할 방식
    • 메모리를 프로세스 크기에 맞게 자르는 가변 분할 방식
  • 재배치

    • 메모리가 꽉 찬 경우 새로운 프로세스를 로드하기 위해 오래된 프로세스를 내보내는 작업
    • 재배치 기준을 따른다.
    • 어떤 프로세스를 메모리에서 내보낼지 결정하는 '재배치 정책'을 따른다.
    • 재배치 정책에서 사용하는 알고리즘을 교체 알고리즘이라고 한다.



## 2. 메모리 주소 ##

(1) 절대 주소와 상대 주소

  • 메모리 영역의 구분

    • 운영체제 영역과 사용자 영역을 구분하여 사용
    • 사용자 프로세스가 운영체제의 영역을 침범하는 일을 막기 위해 경계 레지스터 사용
    • 메모리 관리자는 사용자 요청이 경계 레지스터의 값을 벗어나는지 검사(벗어나면 프롤세스 종료 요청)
  • 절대 주소와 상대 주소의 개념

    • 절대 주소는 메모리 관리자가 바라보는 주소이자 실제 메모리의 물리적 주소
    • 상대 주소는 사용자 프로세스 입장에서 바라보는 주소이며 0번지부터 시작
    • 상대 주소를 사용하는 주소 공간을 논리 주소 공간이라고 한다.
    • ex) 운영체제가 399번지까지 사용하면 프로세스는 400번지부터 적재되기 시작하므로 상대주소가 100번지라면 실제 물리 메모리의 절대 주소는 500번지이다.
  • 프로세스를 실행할 때 메모리 관리자는 재배치 레지스터를 사용하여 상대주소를 물리주소로 변환하여 사용한다.



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

(1) 메모리 오버레이

  • 크기가 큰 프로그램을 적당한 크기로 잘라(여러 모듈로 나눔) 필요한 모듈만 메모리에 올려 사용하는 기법

memory_overlay

  • 프로그램 전체를 메모리에 올리는 것보다 느리지만 메모리가 프로그램보다 작을 때도 실행 가능

  • PC(프로그램 카운터)에 로드 된 명령어에서 필요한 모듈이 메모리에 없으면 메모리 관리자에 요청한다.

  • 가상 메모리의 기본이 되는 개념



(2) 스왑

  • 메모리가 모자라서 쫓겨난 프로세스는 하드디스크의 스왑 영역(swap area)에 저장된다.
    • 스왑 인(swap in), 스왑 아웃(swap out)
    • 스왑 영역은 메모리 관리자가 관리한다.
    • 저장장치는 공간만 빌려준다.
    • ex) 최대 절전 모드는 PC 전원을 OFF하면서 현재 메모리의 데이터를 스왑 영역에 저장해둔다.

swap_area


  • Windows, Unix 계열의 운영체제는 스왑 영역을 디스크의 일부분에 따로 할당해둔다.
    • Unix 계열 운영체제에서는 free 명령어로 스왑 영역의 크기를 확인할 수 있다.
    • Unix 계열 운영체제는 일반적으로 스왑 영역의 크기를 메모리의 2배 정도로 잡는다.



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

(1) 메모리 분할 방식

  • 고정 분할 방식

    • 메모리 영역을 미리 고정된 크기의 여러 파티션으로 나누어놓는 방식
    • 큰 프로세스는 여러 영역에 나누어 할당
    • 큰 프로세스의 경우 연속적이지 않은 메모리 공간에 배치될 수 있어 효율성 감소
    • 메모리 관리가 효율적이고 수월하다.
    • 파티션보다 작은 프로세스의 경우 메모리 낭비 발생
    • 현대 운영체제는 기본적으로 고정 분할 방식이면서 일부분은 가변 분할 방식을 사용
  • 가변 분할 방식

    • 프로세스의 크기에 따라 메모리를 할당하는 방식
    • 한 프로세스가 연속된 공간에 배치되어 메모리 관리 효율성 증가
    • 메모리 관리가 복잡



(2) 가변 분할 방식의 메모리 관리

  • 외부 단편화
    • 프로세스가 들어갈 수 있는 크기가 되지않는 여러 작은 빈 조각들이 발생하는 현상(외부 단편화)

external_fragmentation

  • 메모리 배치 방식

    • 외부 단편화를 해결하기 위해 프로세스를 배치하는 방식
    • 최초 배치, 최적 배치, 최악 배치, 버디 시스템
  • 최초 배치(First Fit)

    • 프로세스 적재 가능한 공간을 순서대로 찾다가 첫 번째로 발견한 공간에 프로세스를 배치
  • 최적 배치(Best Fit)

    • 빈 공간을 모두 확인 후 가능한 가장 작은 공간에 프로세스를 배치
    • 딱 맞는 크기가 없을 경우 외부 단편화로 인한 조각은 작을 것이고 쓸모가 없을 가능성이 높다.
  • 최악 배치(Worst Fit)

    • 빈 공간을 모두 확인 후 가장 큰 공간에 프로세스를 배치
    • 프로세스를 배치하고 남은 공간이 커 쓸모가 있다.

memory_placement

  • 조각 모음
    • 배치 방식을 사용해도 단편화는 발생한다.
    • 조각 모음은 서로 떨어져 있는 빈 조각들을 합치는 작업이다.
    • 조각 모음을 위해 프로세스를 중지시키고, 이동하고, 주소를 바꾸고, 다시 시작해야하는 추가작업 필요
    • 하드디스크에서도 외부 단편화는 발생하여 조각모음을 주기적으로 실행해주는것이 좋다.



(3) 고정 분할 방식의 메모리 관리

  • 내부 단편화
    • 파티션 크기보다 작은 프로세스의 경우 낭비되는 공간 발생
    • 조각 모음을 할 수 없고 다른 프로세스가 사용하는 것도 불가능
    • 분할되는 공간의 크기를 조절하여 내부 단편화를 최소화

internal_fragmentation



(4) 버디 시스템

  • 가변 분할 방식의 외부 단편화를 완화하는 방법

  • 가변 분할 방식과 고정 분할 방식의 중간 구조

    • 프로세스 크기에 맞게 1/2로 메모리를 잘라 나간다.
    • 프로세스에 맞는 적당한 크기가 되었을 때 프로세스를 배치한다.
    • 나뉜 메모리의 각 구역에는 프로세스 1개만 들어간다. 구역내에 빈 자리가 있어도 다른 프로세스가 사용하지 않는다.
    • 프로세스가 종료되면 주변의 빈 조각과 합쳐서 하나의 큰 덩어리를 만든다.

buddy_system

  • 비슷한 크기의 덩어리가 인접한 위치에 존재하기 때문에 통합이 쉽다.

    • 가변 분할에서는 큰 프로세스 사이에 존재해 조각모음을 하기위해 프로세스를 옮겨야한다.
    • 조각 모음을 하지 않아도 큰 덩어리를 만들 수 있다.
  • 그러나 메모리 관리 효율 측면에서는 고정 분할 방식이 더 단순하여 고정 분할 방식이 많이 사용된다.



## 5. 컴파일과 메모리 관리 ##

(1) 컴파일 과정

  • 고급 언어의 소스코드를 번역하여 목적코드 생성
  • 오류가 있는지 점검하고 최적화를 통해 필요 없는 변수와 코드를 삭제
  • 목적 코드에 라이브러리 코드를 삽입하여 최종 실행 파일 생성(링크)



(2) 변수와 메모리 할당

  • 컴파일 과정에서 메모리를 확보하고 정리
    • 심볼 테이블(symbol table) 사용

symbol_table

  • 모든 변수는 메모리 주소로 바뀌어 저장된다.
    • 변수는 단지 프로그래머의 편의성을 위한 것이다.

+ Recent posts