가상 메모리

Jemin·2023년 5월 25일
0

Computer Science

목록 보기
7/31
post-thumbnail

메모리 구조

가상 메모리를 보기 전에 먼저 메모리의 구조부터 알아야 한다.

프로그램이 실행되기 위해서는 먼저 프로그램이 메모리에 로드되어야 한다. 또한 프로그램에서 사용되는 변수들을 저장할 메모리도 필요하다.

따라서, 컴퓨터의 운영체제는 프로그램의 실행을 위해 다양한 메모리 공간을 제공하고 있다. 프로그램이 운영체제로부터 할당받는 대표적인 메모리 공간은 다음과 같다.

  • 코드(Code) 영역

  • 데이터(Data) 영역

  • 스택(Stack) 영역

  • 힙(Heap) 영역

코드(Code) 영역

메모리의 코드 영역은 실행할 프로그램의 코드가 저장되는 영역으로 텍스트 영역이라고도 부른다. CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리하게 된다.

데이터(Data) 영역

메모리의 데이터 영역은 프로그램의 전역 변수와 정적(static) 변수가 저장되는 영역이다. 데이터 영역은 프로그램의 시작과 함께 할당되며, 프로그램이 종료되면 소멸한다.

스택(Stack) 영역

메모리의 스택 영역은 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 영역이다. 스택 영역은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸한다. 이렇게 스택 영역에 저장되는 함수의 호출 정보를 스택 프레임(Stack frame)이라고 한다.

스택 영역은 푸시(push) 동작으로 데이터를 저장하고, 팝(pop) 동작으로 데이터를 인출한다. 이러한 스택은 후입선출(LIFO, Last-In First-Out) 방식에 따라 동작하므로, 가장 늦게 저장된 데이터가 가장 먼저 인출된다. 스택 영역은 메모리의 높은 주소에서 낮은 주소 방향으로 할당된다.

힙(Heap) 영역

메모리의 힙 영역은 사용자가 직접 관리할 수 있는 "그리고 해야만 하는" 메모리 영역이다. 힙 영역은 사용자에 의해 메모리 공간이 동적으로 할당되고 해제된다. 힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.

힙 영역에서 메모리를 동적으로 할당하고 해제하기 위해 일반적으로 mallocfree와 같은 함수를 사용한다.

스택 영역과 힙 영역의 차이

스택 영역과 힙 영역은 메모리의 두 가지 주요 영역이다. 다음은 스택 영역과 힙 영역의 주요 차이점이다.

  1. 데이터 구조:

    • 스택 영역: 후입선출(LIFO) 구조로 데이터를 저장한다. 함수 호출과 관련된 정보(매개변수, 지역 변수, 복귀 주소 등)을 저장하는 데 사용된다.

    • 힙 영역: 동적으로 할당되는 데이터를 저장하는 영역이다. 사용자가 직접 메모리를 할당하고 해제할 수 있다.

  2. 데이터의 크기:

    • 스택 영역: 일반적으로 스택의 크기는 제한적이다. 스택 프레임마다 고정된 크기의 메모리가 할당되며, 스택 오버플로우가 발생할 수 있다.
    • 힙 영역: 힙은 스택보다 큰 메모리 공간을 가질 수 있다. 힙은 필요에 따라 동적으로 메모리를 할당하고 해제할 수 있기 때문에 크기 제한이 더 유연하다.
  3. 데이터의 생명 주기:

    • 스택 영역: 스택 프레임은 함수 호출 및 반환과 관련되어 생명 주기가 관리된다. 함수가 호출되면 해당 함수의 스택 프레임이 생성되고, 함수가 반환되면 스택 프레임이 제거된다.
    • 힙 영역: 힙에 할당된 데이터는 직접 관리해야 한다. 메모리를 동적으로 할당하고 해제하므로 데이터의 생명 주기는 사용자에게 달려있다.
  4. 할당 및 해제:

    • 스택 영역: 스택은 자동으로 메모리를 할당하고 해제한다. 함수가 호출되면 해당 함수의 스택 프레임이 자동으로 생성되고, 함수가 반환되면 스택 프레임이 자동으로 제거된다.
    • 힙 영역: 힙은 사용자가 직접 메모리를 할당하고 해제해야 한다. 동적으로 메모리를 할당하고 해제하는 함수 또는 연산자를 사용해야 한다.

요약하면, 스택 영역은 함수 호출과 관련된 정보를 저장하고 LIFO 구조로 동작하며 크기가 제한적이다. 힙 영역은 동적으로 할당되는 데이터를 저장하고 사용자가 직접 메모리를 할당하고 해제할 수 있으며 크기가 더 유연하다.

추가적으로, 스택 영역은 컴파일러 및 프로세서의 지원을 받아 엑세스 속도가 빠르고 할당 및 해제 오버헤드가 낮은 장점이 있다. 반면 힙 영역은 자유로운 동적 메모리 할당이 가능하다는 장점이 있지만 엑세스 속도가 느리고 할당 및 해제에 메모리 관리자나 가비지 컬렉터의 개입이 필요하기 때문에 오버헤드가 큰 단점이 있다. 개발자는 이러한 특성을 고려하여 데이터의 사용 패턴과 요구 사항에 맞게 적절한 메모리 영역을 선택하고 활용해야 한다.

가비지 컬렉터(GC)

가비지 컬렉터는 동적으로 할당된 메모리 중에서 더 이상 사용되지 않는 메모리를 자동으로 해제하는 기능을 제공한다.

프로그램이 실행되면서 메모리를 할당하고 사용하는 과정에서 더 이상 참조되지 않는 객체 또는 데이터가 발생할 수 있는데, 이러한 상황에서 가비지 컬렉터는 해당 객체 또는 데이터를 감지하고, 자동으로 그들이 사용하던 메모리를 해제한다. 이를 통해 메모리 누수를 방지하고, 사용되지 않는 메모리 공간을 효율적으로 회수하여 다시 사용할 수 있게 된다.

가비지 컬렉터는 언어나 런타임 환경에 따라 다양한 방식으로 구현될 수 있으며, 대부분의 현대적인 프로그래밍 언어들은 가비지 컬렉션 기능을 내장하고 있다. 이를 통해 개발자는 명시적으로 메모리를 해제하는 작업에 대한 부담을 줄이고, 프로그램의 안전성과 생산성을 향상시킬 수 있다.

가상 메모리(Virtual Memory)

가상 메모리는 운영체제에서 제공하는 추상화된 메모리 개념이다. 실제 물리적인 메모리(RAM)보다 큰 용량의 메모리 공간을 프로세스에게 제공하는 기술이다. 이를 통해 여러 프로세스가 동시에 실행될 때 더 많은 메모리를 사용할 수 있다.

가상 메모리의 핵심은 필요한 부분만 메모리에 적재(부분 적재)하는 것이다.

애플리케이션이 실행될 때, 실행에 필요한 일부분만 메모리에 올라가며 애플리케이션의 나머지는 디스크에 남게 된다. 즉, 디스크가 RAM의 보조기억장치처럼 작동하는 것이다.

가상 메모리의 장점

가상 메모리는 다음과 같은 장점을 제공한다.

  1. 더 큰 메모리 공간: 가상 메모리를 사용하면 물리 메모리보다 더 큰 용량의 메모리 공간을 사용할 수 있다. 이는 여러 프로세스가 큰 메모리 요구를 충족할 수 있게 해준다.

  2. 메모리 관리의 유연성: 가상 메모리는 프로세스에게 독립적인 주소 공간을 제공하기 때문에 각 프로세스가 자신만의 가상 주소 공간을 사용할 수 있다. 이는 메모리 관리를 용이하게 만들어 준다.

  3. 효율적인 메모리 관리: 가상 메모리는 페이지 단위로 관리되며, 필요한 페이지만 물리 메모리에 로드된다. 필요하지 않은 페이지는 보조기억장치에 저장되어 필요할 때 로드한다. 이를 통해 실제로 필요한 메모리만 사용하고 나머지는 저장장치에 보관하여 효율적인 메모리 사용을 가능하게 한다.

  4. 보호 기능: 가상 메모리는 각 프로세스에게 독립적인 주소 공간을 제공하므로 한 프로세스의 메모리 접근이 다른 프로세스에 영향을 미치지 않는다. 이를 통해 프로세스 간의 보호와 안정성을 유지할 수 이싿.

가상 메모리는 운영체제의 핵심 기술 중 하나로, 현대의 다중 프로그래밍 환경에서 메모리 관리와 성능 향상을 위해 널리 사용되고 있다.

추상화(Abstract)

가상 메모리는 추상화 기법을 사용하여 물리적인 메모리와 프로세스에 대한 가상화된 메모리 공간을 제공한다. 이를 통해 각 프로세스는 자신만의 독립적인 메모리 공간을 가지고 있는 것처럼 동작하며, 물리적인 메모리 관리와 프로세스 간의 충돌을 피할 수 있다. 또한, 가상 메모리는 메모리 관리의 효율성을 높이고, 여러 프로세스가 동시에 실행할 수 있는 환경을 제공한다.

가상 주소 공간(Virtual Addrss Space)

가상 메모리는 프로세스에게 가상 주소 공간을 제공한다. 가상 주소 공간은 연속된 주소 범위로 나타나지만 실제로는 물리적인 메모리에 연속적으로 할당되지 않는다. 대신 운영체제가 가상 주소를 물리 주소로 변환하는 매핑을 수행한다.

프로세스의 주소 공간은 페이지(page) 단위로 관리된다. 가상 주소 공간의 주소를 논리 주소라고 하는데, 모든 논리 주소가 반드시 물리적인 메모리의 물리 주소로 할당받는 것은 아니다. 가상 주소 공간의 페이지가 물리 주소 공간에 할당되지 않은 케이스는 다음과 같다.

  • 필요할 때 물리 주소 할당 받는 경우

  • 접근 금지 페이지로 남겨준 경우

  • 사용되지 않은(unused) 논리 주소인 경우

MMU(Memory Management Unit)

CPU에 코드 실행시, 가상 주소 메모리 접근이 필요할 때, 해당 주소를 물리 주소 값으로 변환해 주는 하드웨어 장치다. 즉, CPU는 가상 메모리를 다루고, 가상 메모리의 가상 주소에 접근 시 MMU 하드웨어를 통해 물리 주소로 변환되어 물리 메모리에 접근한다.

가상 주소 공간의 구조

4GB로 가정한 가상 주소 공간의 구조는 크게 사용자 영역과 커널 영역으로 나눌 수 있다. 가상 메모리가 할당되면 2GB의 사용자 영역과 2GB의 커널 영역으로 나누어 진다.

  • 사용자 영역: 보통 사용하는 일반 응용 프로그램들의 사용 공간이다. 위에서 정리한 메모리 구조와 같은 구조를 가지고 있다.

    • 0x00000000 ~ 0x7FFFFFFF
  • 커널 영역: 단일 공간으로 kernel-mode를 사용하는 모든 프로세스에서 공유되며, 커널 영역은 공유되면서 시스템 운영에 필수적이기 때문에 주로 페이지 파일보다는 RAM에 존재하고 있다.

    • 0x80000000 ~ 0xFFFFFFFF

요구 페이징(Demand Paging)

요구 페이징은 가상 메모리 관리 기법 중 하나로, 프로세스가 실행되는 동안 필요한 페이지만 실제 메모리에 올리는 기법이다. 전체 프로세스의 모든 페이지를 처음부터 메모리에 올리는 것이 아니라, 페이지 부재(Page Fault)가 발생할 때 해당 페이지를 디스크에서 읽어와 메모리에 올린다.

요구 페이징 동작 과정

요구 페이징은 다음과 같은 과정으로 동작한다.

  1. 프로세스 실행 시작: 프로세스가 실행되면 처음에는 필요한 페이지가 메모리에 없다. 이 때는 페이지 테이블에 있는 페이지 테이블 엔트리(PTE)를 통해 어떤 페이지가 요청되는지 확인한다.

  2. 페이지 부재(Page Fault) 발생: 필요한 페이지가 메모리에 없는 경우 페이지 부재가 발생한다. 이 때 운영체제는 페이지 부재 핸들러를 통해 요청된 페이지가 디스크에 있는지 확인하고, 디스크에서 해당 페이지를 읽어와 메모리에 할당한다.

  3. 페이지 테이블 갱신: 페이지가 메모리에 올라왔으면 페이지 테이블의 해당 엔트리를 갱신한다. 이로써 페이지 테이블은 가상 주소와 실제 메모리 주소 간의 매핑을 유지한다.

  4. 프로세스 실행 계속: 필요한 페이지가 메모리에 올라온 후에는 프로세스가 정상적으로 실행된다. 필요한 페이지가 추가로 요청되면 위의 과정을 반복한다.

요구 페이징은 메모리 사용 효율성을 높이고, 실제 필요한 페이지만 메모리에 올리기 때문에 메모리 관리 비용을 줄일 수 있다. 또한, 대부분의 프로세스가 실행되는 동안 일부 페이지만 필요하거나 사용되지 않는 페이지가 있을 수 있는 경우에 유용하다.

프로세스를 실행 시 모든 부분이 필요한 것이 아니기 때문에 실행 시 필요한 부분만 메모리에 올림으로써, 메인 메모리에 올라가는 프로세스의 크기를 줄일 수 있다.

요구 페이징은 실행시킬 프로세스들을 페이징 과정을 통해 외부 단편화 문제를 해결한다. 따라서 프로세스를 페이지 단위로 나누어 실행에 필요한 부분과 필요 없는 부분으로 나눈다. 이 때 당장 실행에 필요한 페이지만 메모리에 적재하는 기법이 요구 페이징이다. 당장 실행에 필요 없는 부분은 Backing Store에 저장해놓았다가 필요할 때 메모리에 올리게 된다.

페이지 부재(Page Fault)

페이지 부재는 요구 페이징에서 발생하는 현상으로, 프로세스가 실행 중에 필요한 페이지가 현재 메모리에 없는 상태이다. 이때 운영체제는 요청된 페이지를 디스크에서 읽어와 메모리에 적재하여 프로세스의 실행을 지원한다.

페이지 부재의 처리 과정

페이지 부재가 발생하면 다음과 같은 과정이 진행된다.

  1. 페이지 부재 발생: 프로세스가 특정 페이지를 요청하는데, 해당 페이지가 현재 메모리에 없는 경우 페이지 부재가 발생한다. 이는 프로세스가 메모리에 접근하려는 페이지가 아직 디스크에 저장되어 있음을 의미한다.

  2. 페이지 부재 핸들링: 페이지 부재가 발생하면 운영체제는 페이지 부재 핸들러를 통해 이를 처리한다. 핸들러는 다음과 같은 작업을 수행한다.

    • 요청된 페이지가 디스크에 있는지 확인한다.

    • 디스크에 해당 페이지를 읽어와 메모리에 할당한다. 이 과정을 페이지 스와핑(Page Swapping)이라고도 한다.

    • 페이지 테이블을 업데이트하여 가상 주소와 실제 메모리 주소 간의 매핑을 수행한다.

    • 프로세스의 실행을 재개한다.

  3. 페이지 부재 해결: 페이지 부재가 해결되면 프로세스는 요청한 페이지에 접근하여 필요한 데이터를 읽거나 쓸 수 있게 된다. 페이지 부재가 발생한 지점에서 프로세스의 실행을 계속 진행한다.

페이지 부재는 메모리 용량 제한으로 인해 모든 페이지를 한 번에 메모리에 올릴 수 없는 경우에 발생한다. 대부분의 프로세스는 실행되는 동안 모든 페이지를 동시에 필요로 하지 않기 때문에 요구 페이징이라는 기법을 통해 필요한 페이지만 메모리에 올리고 필요한 순간에 페이지 부재가 발생하면 해당 페이지를 메모리로 가져온다.

페이지 부재가 빈번하게 발생할 경우 디스크 I/O 비용이 증가하여 성능 저하가 발생할 수 있으므로, 페이지 교체 알고리즘 등을 통해 최적화 하는 것이 중요하다.

페이지 교체 알고리즘

  • FIFO(First-In First-Out): 가장 오래된 페이지를 교체하는 알고리즘이다. 페이지가 메모리에 들어온 시점을 기준으로 교체된다. FIFO 알고리즘은 구현이 간단하고 공정한 성격을 가지지만, 오래된 페이지가 최근에 자주 사용된 페이지일 경우 교체가 불필요하게 발생할 수 있다.

  • LRU(Least Recently Used): 가장 오랫동안 참조되지 않은 페이지를 교체하는 알고리즘이다. 페이지가 가장 오래 사용되지 않은 시점을 기준으로 교체된다. LRU 알고리즘은 최적의 페이지 교체 알고리즘이지만, 모든 페이지의 참조 시간을 추적해야 하므로 구현이 복잡하고 오버헤드가 큰 단점이 있다.

  • LFU(Least Frequently Used): 가장 적게 참조된 페이지를 교체하는 알고리즘이다. 페이지가 참조된 횟수를 기준을 교체된다. LFU 알고리즘 최근에 자주 사용되었던 페이지가 오랫동안 사용되지 않을 경우 교체할 수 있는 장점이 있지만, 페이지 참조 횟수를 추적해야 하므로 구현이 복잡하고 오버헤드가 큰 단점이 있다.

  • Optimal: 가장 최적의 페이지를 교체하는 알고리즘이다. 앞으로 가장 오랫동안 사용되지 않을 페이지를 교체한다. Optimal 알고리즘은 이론적으로 가장 좋은 성능을 보이지만, 실제로는 모든 페이지 참조를 예측해야 하므로 구현이 어렵고 비현실적이다.

이외에도 Clock 알고리즘, Second-Chance 알고리즘, Random 알고리즘 등 다양한 페이지 교체 알고리즘이 있다.

참고
[컴퓨터시스템] 가상메모리 (Virtual Memory)
[운영체제] 가상 메모리란?
[운영체제] 가상 메모리(Virtual Memory System)
가상 주소 공간 (VAS, Virtual Address Space)
요구 페이징(가상메모리)

profile
경험은 일어난 무엇이 아니라, 그 일어난 일로 무엇을 하느냐이다.

0개의 댓글