5/14 가상 메모리, 페이징(PAGING)

JK·2023년 5월 15일
0

가상 메모리

가상 메모리(Virtual Memory)는 프로그램이 실행될 때 필요한 모든 메모리 공간을 미리 할당하지 않고 필요할 때 동적으로 할당하는 기술입니다. 이를 통해 물리적인 메모리(RAM)보다 큰 용량의 가상 메모리 공간을 확보할 수 있습니다.

가상 메모리는 주소 공간(Address Space)을 사용하여 구현됩니다. 각 프로세스는 독자적인 주소 공간을 가지며, 이 주소 공간은 논리적인 주소(Logical Address)와 물리적인 주소(Physical Address)를 매핑하는 페이지(Page)로 구성됩니다.

프로세스는 논리적인 주소를 사용하여 메모리에 접근하며, 이 때 가상 메모리 관리자(Virtual Memory Manager)는 논리적인 주소를 물리적인 주소로 변환합니다. 이 변환 작업은 페이지 테이블(Page Table)을 사용하여 이루어지며, 페이지 테이블은 각 페이지의 논리적인 주소와 물리적인 주소를 매핑하는 역할을 합니다.

또한 가상 메모리는 페이지 교체(Paging)와 스와핑(Swapping)을 이용하여 메모리 공간을 관리합니다. 페이지 교체는 메모리에 올라와 있는 페이지 중에 사용되지 않는 페이지를 디스크에 저장하고, 필요한 페이지를 메모리로 로드하여 교체하는 작업을 의미합니다. 스와핑은 현재 실행 중인 프로세스의 일부나 전체를 디스크로 옮기는 작업으로, 메모리 부족 상황에서 사용됩니다.

가상 메모리는 메모리 용량의 한계를 극복하고, 다양한 프로그램들이 동시에 실행될 수 있도록 하는 중요한 기술입니다.


예제 코드

가상 메모리를 다루는 예제 코드 입니다. 이 예제에서는 메모리에 100바이트의 공간을 할당하고, 그 공간을 4바이트씩 나누어 사용하도록 하겠습니다.

#include <stdio.h>
#include <stdlib.h>

int main() {
    int *ptr = (int *) malloc(100); // 100바이트의 공간 할당

    // 4바이트씩 나누어서 사용
    ptr[0] = 1;
    ptr[1] = 2;
    ptr[2] = 3;
    ptr[3] = 4;

    printf("%d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]);

    free(ptr); // 메모리 해제

    return 0;
}

이 코드에서 malloc() 함수를 사용하여 100바이트의 공간을 할당합니다. 그리고 ptr 포인터를 통해 그 공간을 4바이트씩 나누어 사용합니다. 이렇게 할당된 메모리는 가상 메모리에 위치하며, 운영체제가 이를 물리 메모리에 매핑하여 사용합니다. 이렇게 하면 실제 물리 메모리보다 큰 메모리 공간을 사용할 수 있습니다. 마지막으로 free() 함수를 사용하여 할당된 메모리를 해제합니다


페이징(PAGING)

페이징(Paging)은 가상 메모리의 한 기법으로, 프로그램이 실행될 때 필요한 데이터와 코드를 저장하고 있는 물리적인 메모리 공간을 페이지(Page)라는 고정 크기의 블록으로 분할하여 가상 메모리에 매핑하는 기법입니다.

일반적으로 가상 메모리는 프로세스가 사용하는 물리 메모리보다 큰 크기를 가집니다. 이는 프로세스의 실행에 필요한 모든 데이터와 코드를 미리 메모리에 적재하지 않고 필요한 시점에 페이지 단위로 메모리에 올리기 때문입니다. 이러한 페이징 기법을 사용하면 물리 메모리를 효율적으로 사용할 수 있습니다.

페이징 기법은 가상 메모리를 페이지 단위로 나누어서 사용하는데, 각 페이지의 크기는 일반적으로 4KB, 8KB, 16KB 등의 크기로 정해집니다. 이렇게 나누어진 페이지는 페이지 번호(Page Number)와 같은 식별자로 사용됩니다. 따라서 가상 메모리에서는 논리적 주소가 페이지 번호와 오프셋(Offset)으로 나뉘어지게 됩니다.

페이징 기법은 물리 메모리에 더 이상 사용 가능한 공간이 없을 때, 메모리에서 페이지를 제거하고 가상 메모리에 저장하는 기능을 제공합니다. 이러한 과정을 페이지 교체(Page Replacement)라고 합니다. 페이지 교체 알고리즘은 페이지 폴트(Page Fault)가 발생할 때마다 실행되며, 가장 최근에 사용하지 않은 페이지를 교체함으로써 메모리 공간을 확보합니다.

예를 들어, 10MB 크기의 프로그램을 실행하고 있는데, 물리 메모리는 8MB 밖에 사용하지 못한다면, 나머지 2MB는 가상 메모리에서 사용됩니다. 이때 프로그램이 실행될 때 필요한 데이터와 코드는 페이지 단위로 나뉘어져 가상 메모리에 매핑되며, 필요한 페이지가 물리 메모리에 없으면 페이지 폴트가 발생하여 해당 페이지를 물리 메모리에 로딩합니다.


예제 코드

다음은 페이징을 다루는 예제 코드 입니다. 32비트 시스템에서 4KB 크기의 페이지로 메모리를 관리하는 가상 메모리 시스템의 예제 코드입니다. 페이지 번호를 기반으로 가상 주소를 처리하는 방식으로 구현하였습니다.

#include <stdio.h>
#include <stdlib.h>

#define PAGE_SIZE 4096 // 4KB
#define PAGE_NUM 256   // 총 페이지 수

typedef struct {
    int pfn;   // 페이지 프레임 번호
    int valid; // 페이지의 유효 여부
} PageTableEntry;

PageTableEntry pageTable[PAGE_NUM];

int main() {
    int address;
    int pageNumber, offset;
    
    while (1) {
        printf("가상 주소를 입력하세요 (종료는 -1): ");
        scanf("%d", &address);

        if (address == -1) break;
        
        pageNumber = address / PAGE_SIZE;
        offset = address % PAGE_SIZE;
        
        if (pageTable[pageNumber].valid) { // 페이지가 메모리에 올라와 있으면
            int physicalAddress = pageTable[pageNumber].pfn * PAGE_SIZE + offset;
            printf("물리 주소: %d\n", physicalAddress);
        } else { // 페이지 부재 발생
            printf("페이지 부재 발생!\n");
            // 페이지 교체 알고리즘 수행
            pageTable[pageNumber].pfn = rand() % 128; // 임의의 페이지 프레임 번호 할당
            pageTable[pageNumber].valid = 1; // 유효한 페이지로 설정
            int physicalAddress = pageTable[pageNumber].pfn * PAGE_SIZE + offset;
            printf("물리 주소: %d\n", physicalAddress);
        }
    }
    
    return 0;
}

이 예제 코드에서는 페이지 테이블을 배열로 구현하여 페이지 번호와 페이지 프레임 번호, 유효 여부를 저장하고 있습니다. 주소가 입력되면 페이지 번호와 오프셋을 계산하고, 페이지 테이블을 조회하여 페이지가 메모리에 올라와 있는지 여부를 판단합니다. 페이지가 메모리에 올라와 있으면 페이지 프레임 번호와 오프셋을 이용하여 물리 주소를 계산하고 출력하고, 페이지 부재가 발생하면 임의의 페이지 프레임 번호를 할당하고 페이지를 유효한 페이지로 설정한 후 물리 주소를 계산하여 출력합니다.


가상 메모리와 페이징을 공부하면서 어려웠던 점은 처음에 개념을 이해하는 것이 어려웠다는 점입니다. 특히, 메모리 관리와 하드웨어 시스템이 함께 동작하는 방식이 복잡하게 느껴졌습니다. 또한, 페이징 테이블과 페이지 디렉터리 등의 용어와 구조도 이해하기가 쉽지 않았습니다.

하지만, 가상 메모리와 페이징이 어떻게 동작하는지 이해하면 운영 체제의 성능을 최적화하고 메모리 관리를 효율적으로 할 수 있다는 것을 깨달았습니다. 또한, 하드웨어와 소프트웨어가 서로 상호작용하는 구조를 이해하는 데 도움이 되었습니다.

이러한 개념을 이해하고 구현하는 것은 어려웠지만, 페이징 예제 코드를 작성하고 디버깅하는 과정에서 프로그래밍 능력이 향상되었습니다. 디버깅 과정에서 하드웨어와 소프트웨어가 상호작용하는 구조를 이해하면서, 컴퓨터 시스템에 대한 이해도도 향상되었습니다.

profile
^^

0개의 댓글