물리 메모리 관리

컴공생의 코딩 일기·2023년 5월 9일
0

운영체제

목록 보기
5/9

메모리 관리의 개요

메모리 이해하기

  • 메모리의 구조는 1바이트(B) 크기를 나뉜다.
  • 1B로 나뉜 각 영역은 주소(address)로 구분되고 보통 0번지 부터 시작한다.
  • CPU는 메모리에 있는 데이터를 가져오거나 작업 결과를 메모리에 저장하기 위해 주소를 사용한다.

메모리 관리

메모리 관리 시스템(memory management system)이란 컴퓨터 시스템에서 메모리를 효율적으로 사용하고 관리하기 위한 기술이다. 메모리 관리 시스템의 주요 목표는 프로세스 간 메모리 공간을 할당하고, 사용되지 않는 메모리를 회수하며, 메모리의 효율적 활용을 위해 조정하는 것이다.

메모리 관리 시스템은 다양한 기능을 제공한다:

  1. 메모리 할당(Allocation): 프로그램이나 프로세스가 실행될 때 필요한 메모리 공간을 할당한다.
  2. 메모리 보호(Protection): 각 프로세스가 다른 프로세스의 메모리 영역에 접근하지 못하도록 보호한다.
  3. 메모리 공유(Sharing): 여러 프로세스가 특정 메모리 영역을 공유할 수 있도록 지원한다.
  4. 메모리 회수(Deallocation): 프로세스가 종료되거나 필요하지 않게 되면 메모리를 회수하여 다른 프로세스에 재사용할 수 있도록 한다.

메모리 관리 시스템은 컴퓨터 시스템의 운영 체제(OS)에서 주로 관리되며, 하드웨어와 소프트웨어 모두에서 지원된다. 이를 통해 시스템 성능을 향상시키고 자원을 최적화하는 데 도움이 된다.

메모리 관리의 이중성

메모리 관리의 이중성은 시스템 성능과 메모리 사용 효율 사이의 균형을 찾아야 하는 메모리 관리 전략의 중요한 측면이다. 이를 위해 다양한 메모리 관리 기법이 공간 효율성(메모리 낭비 최소화)과 시간 효율성(빠른 메모리 접근) 사이의 최적의 절충안을 찾으려고 노력한다.

소스코드의 번역과 실행

  • 저급언어(low level language): 기계어, 어셈블리어
  • 고급언어(hight level language): C언어, 자바 ...
  • 컴파일러(compiler): 소스코드를 컴퓨터가 실행할 수 있는 기계어로 번역한 후 한꺼번에 실행
    • C언어, 자바
  • 인터프린터(interpretor): 소스코드를 한 행씩 번역하여 실행
    • 자바스크립트, 파이썬

컴파일러 방식

컴파일러는 실행 전에 소스 코드를 점검하여 오류를 수정하고 필요 없는 부분을 정리하여 최적화된 실행 파일을 만든다.

  • 오류 발견: 심벌 테이블(symbol table)을 사용
    • 심벌 테이블: 변수 선언부에 명시한 각 변수의 이름과 종류(type)을 모아놓은 테이블, 선언하지 않은 변수를 사용하지는 않았는지, 변수에 다른 종류에 다른 종류의 데이터를 저장하지 않았는지 알 수 있다.
  • 소스코드 최적화

컴파일러를 사용하는 언어는 사용할 변수를 먼저 선언한 후 코드를 작성해야 한다.

컴파일러의 컴파일 과정

  1. 어휘 분석(Lexical Analysis): 소스 코드를 읽어 토큰(token)이라 불리는 의미 있는 요소로 분리한다. 이 단계에서 주석, 공백 등은 제거된다.

  2. 구문 분석(Parsing): 어휘 분석에서 생성된 토큰들을 구문 규칙(syntax)에 따라 추상 구문 트리(Abstract Syntax Tree, AST)와 같은 중간 표현 형태로 변환한다.

  3. 의미 분석(Semantic Analysis): 추상 구문 트리에서 의미 오류를 검사하고, 변수와 함수의 정의 및 사용에 대한 정보를 확인한다. 이 과정에서 타입 검사(type checking)도 수행된다.

  4. 중간 코드 생성(Intermediate Code Generation): 의미 분석을 통해 검증된 추상 구문 트리를 중간 코드(Intermediate Code)로 변환한다. 이 중간 코드는 소스 코드와 기계어 사이의 표현이며, 이를 통해 최적화 및 기계어 변환을 수행합니다.

  5. 코드 최적화(Code Optimization): 중간 코드를 분석하여 불필요한 연산이나 반복을 제거하고, 코드의 효율성을 높이는 최적화 작업을 수행한다.

  6. 목적 코드 생성(Target Code Generation): 최적화된 중간 코드를 기계어로 변환하여 실행 가능한 목적 코드(Object Code)를 생성합니다. 이 단계에서 메모리 주소 및 레지스터 할당이 이루어진다. 확장자는 obj다.

  7. 링킹(Linking): 목적 코드와 필요한 라이브러리 파일을 연결해 완전한 실행 파일을 생성한다. 이 과정에서 함수 호출 및 라이브러리 참조를 해결하며, 최종 실행 파일이 생성된다.

    동적 라이브러리(dynamic library)는 프로그램 실행 중에 필요한 코드나 데이터를 로드하고 사용할 수 있는 라이브러리다. 동적 라이브러리는 공유 라이브러리(shared library)라고도 불리며, 확장자로 .so (리눅스), .dll (윈도우) 등을 사용한다.

메모리 관리 작업

  • 메모리 가져오기(fetch): 실행할 프로세스와 데이터를 가져오는 작업
  • 메모리 배치(placement): 가져온 프로세스와 데이터를 메모리의 어떤 부분에 올려놓을지 결정하는 작업
    • 페이징(paging): 메모리를 같은 크리고 자르는 것
    • 세그먼테이션(segmentation): 프로세스의 크기에 맞게 자르는 것
  • 메모리 재배치: 꽉 찬 메모리에 새로운 프로세스를 가져오기 위해 오래된 프로세스를 내보내는 작업
    • 교체 알고리즘(replacement algorithm)

메모리 주소

메모리를 접근할 때는 주소를 이용한다. 메모리 주소는 물리 주소와 논리 주소로 나뉜다.

32bit CPU와 64bit CPU의 차이

CPU를 나타낼 때 비트(bit)는 CPU가 한 번에 다룰 수 있는 최대 크기를 의미한다.

논리주소와 물리주소

논리 주소(logical address):
논리 주소는 프로세스에 의해 생성되고 사용되는 주소이다. 프로세스는 가상 메모리 공간에서 실행되며, 논리 주소는 이 가상 메모리 공간에서 데이터를 찾기 위해 사용된다. 논리 주소는 CPU에 의해 생성되며, 가상 메모리 관리 시스템을 사용하여 물리 주소로 변환된다. (각 프로그램 마다 0번지 부터 시작하는 주소)

물리 주소(physical address):
물리 주소는 실제 메모리 하드웨어(예: RAM)에 저장된 데이터의 위치를 나타낸다. 논리 주소가 물리 주소로 변환되면, 컴퓨터는 실제 메모리에서 해당 데이터를 읽거나 쓸 수 있다. 물리 주소는 메모리 관리 장치(MMU)를 통해 논리 주소에서 파생된다.

경계 레지스터 (boundary register)

경계 레지스터(boundary register)는 메모리 프로텍션 및 관리에 사용되는 하드웨어 레지스터이다. 이 레지스터는 프로세스가 할당받은 메모리 영역의 경계를 저장하며, 프로세스가 다른 프로세스의 메모리 공간에 접근하지 못하도록 보호하는 역할을 한다.

경계 레지스터는 주로 베이스 레지스터(base register)와 함께 사용되어 메모리 접근을 관리한다. 베이스 레지스터는 프로세스가 할당받은 메모리 공간의 시작 주소를 저장하고, 경계 레지스터는 해당 메모리 공간의 크기 또는 끝 주소를 저장한다.

프로세스가 메모리에 접근하려 할 때, 베이스 레지스터와 경계 레지스터의 값은 CPU에 의해 비교된다. 만약 접근하려는 주소가 베이스 레지스터와 경계 레지스터가 나타내는 영역 내에 있으면, 메모리 접근이 허용된다. 그렇지 않으면 메모리 접근이 거부되고 오류가 발생한다.

이와 같이 경계 레지스터는 메모리 프로텍션 및 관리를 위해 사용되며, 프로세스가 할당받은 메모리 영역의 경계를 저장하여 프로세스 간 메모리 공간의 침범을 방지한다.

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

메모리 오버레이

메모리 오버레이(memory overlay)는 컴퓨터 프로그램이 메모리 부족 문제를 해결하기 위해 사용하는 기법이다. 이 기법은 주로 작은 메모리 용량을 가진 시스템에서 큰 프로그램을 실행할 때 사용되며, 메모리에 동시에 저장할 수 없는 프로그램의 여러 부분을 시간에 따라 교체하며 실행한다.

메모리 오버레이의 주요 개념은 프로그램을 여러 개의 작은 모듈로 분리한 다음, 필요할 때 마다 모듈을 메모리에 가져와 사용한다

스왑

스왑(swap)은 컴퓨터에서 메모리 관리를 위해 사용되는 기법으로, 물리 메모리(RAM)가 부족할 때 디스크 공간을 사용하여 프로세스와 데이터를 일시적으로 저장하는 과정이다. 스왑은 가상 메모리 시스템에서 중요한 역할을 하며, 메모리를 효율적으로 사용하고 더 많은 프로세스를 실행할 수 있게 한다.

스왑 과정은 다음과 같다:

  1. 물리 메모리가 부족한 상황이 발생하면, 운영 체제는 사용 중인 메모리 중 일부를 디스크의 스왑 영역(swap area)으로 이동시킨다. 이를 스왑 아웃(swap out)이라고 한다.

  2. 필요한 프로세스나 데이터가 스왑 영역에 있는 경우, 운영 체제는 디스크에서 해당 프로세스나 데이터를 다시 물리 메모리로 불러온다. 이를 스왑 인(swap in)이라고 한다.

스왑을 사용하면 물리 메모리가 부족할 때 추가적인 메모리 공간을 확보할 수 있지만, 디스크에 접근하는 속도가 물리 메모리에 접근하는 속도보다 훨씬 느리기 때문에 성능 저하가 발생할 수 있다 따라서 스왑은 메모리 부족 문제를 해결하는 일시적인 방법으로 사용되며, 성능을 향상시키려면 물리 메모리 용량을 늘리는 것이 좋다.

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

  • 가변 분할 방식(variable-size partitioning): 프로세스의 크기에 따라 메모리를 나눈다.
  • 고정 분할 방식(fixed-size partitioning): 프로세스의 크기와 상관없이 메모리를 같은 크기로 나눈다.

가변 분할 방식(variable partitioning method)과 고정 분할 방식(fixed partitioning method)은 메모리 관리에서 사용되는 두 가지 주요 분할 방식입니다. 이들 방식은 각각 다음과 같은 특징을 가집니다.

  1. 가변 분할 방식(variable partitioning method):
    가변 분할 방식에서는 프로세스가 필요로 하는 정확한 메모리 크기만큼 할당받는다. 프로세스의 크기에 따라 메모리를 동적으로 분할하며, 메모리 사용 효율이 높다. 가변 분할 방식은 최초 배치(First Fit), 최적 배치(Best Fit), 최악 배치(Worst Fit) 등의 할당 알고리즘을 사용할 수 있다. 가변 분할 방식의 단점은 외부 단편화(external fragmentation)가 발생할 수 있다는 것이다. 이는 메모리 공간이 쪼개져 사용되기 때문에 발생한다.

    외부 단편화(external fragmentation): 조각이 프로세스의 바깥쪽에 위치 하는 것

  • 최초 배치(First Fit):
    최초 배치 알고리즘은 메모리를 순차적으로 검색하여 프로세스가 사용할 수 있는 충분한 공간을 찾는 첫 번째 빈 메모리 공간에 할당하는 방식.

  • 최적 배치(Best Fit):
    최적 배치 알고리즘은 프로세스가 필요로 하는 메모리 크기에 가장 가까운 빈 메모리 공간을 찾아 할당하는 방식.

  • 최악 배치(Worst Fit):
    최악 배치 알고리즘은 사용 가능한 빈 메모리 공간 중 가장 큰 공간에 프로세스를 할당하는 방식.

조각 모음(defragmentation)

조각 모음(defragmentation)은 서로 떨어져 있는 여러 개의 빈 공간을 합치는 작업이다.
조각 모음은 다음과 같은 순서로 진행된다.
1. 조각 모음을 하기 위해 이동할 프로세스의 동작을 멈춘다.
2. 프로세스를 적당한 위치로 이동한다. 프로세스가 원래의 위치에서 이동하기 때문에 프로세스의 논리 주소 값을 바꾼다.
3. 앞의 1, 2 작업을 다 마친 후 프로세스를 다시 시작한다.

  1. 고정 분할 방식(fixed partitioning method):
    고정 분할 방식에서는 메모리가 고정 크기의 파티션으로 나누어진다. 프로세스는 이러한 파티션 중 하나에 할당되며, 파티션의 크기보다 작은 프로세스만 할당할 수 있다. 고정 분할 방식은 구현이 간단하고 내부 단편화(internal fragmentation)가 발생할 수 있다. 내부 단편화는 프로세스가 파티션의 전체 공간을 사용하지 못해 발생하는 메모리 낭비다. 고정 분할 방식은 페이징(paging) 기법을 사용한다.

버디 시스템

버디 시스템은 가변 분할 방식과 고정 분할 방식의 중간 구조다.

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

0개의 댓글