Skip to main content

리눅스의 메모리 관리

하드웨어를 제어하기 위해 메모리를 읽는 이유

하드웨어를 제어하기 위해 메모리를 읽는 것은 Memory Mapped I/O (MMIO) 방식 때문이다. I/O 입출력 뿐만 아니라 하드웨어의 레지스터가 메모리 주소에 매핑되어서 하드웨어 레지스터 주소를 읽고 해당 주소를 통해서 하드웨어에 접근한다.

MMIO를 사용하는 이유

  1. 메모리와 I/O를 동일한 주소 공간에서 관리 가능
  2. 일반적인 메모리 명령어로 I/O 접근 가능
  3. 메모리 보호 및 가상 메모리 메커니즘 활용 가능
  4. 캐시 제어가 용이함

CPU가 메모리를 읽는 과정

  1. CPU가 메모리 접근을 요청할 때, MMU는 먼저 TLB를 확인하여 필요한 매핑 정보를 찾음
  • 메모리 접근 시 가상 주소 변환 과정
    • CPU 가상 주소 생성
    • MMU는 가상 주소를 사용해 페이지 테이블 참조
    • 페이지 테이블은 가상 메모리 페이지와 해당하는 물리적 페이지의 매핑 보관
    • VPN(가상 페이지 번호)는 물리적 페이지 번호(PPN)으로 변환
    • 변환된 물리적 주소는 메모리에 실제로 접근하기 위해 사용
  1. TLB에서 해당 정보를 찾지 못하면 TLB 미스 발생
  2. 전체 페이지 테이블을 검색해서 필요한 매핑 정보를 찾아내고 이 정보를 TLB에 로드하여 다음 번 요청 시 빠르게 접근

만약 3번 과정에서도 페이지를 찾지 못할 경우, 페이지 폴트가 발생

memory

  1. TLB 미스와 페이지 테이블 조회

    찾으려는 페이지가 TLB(페이지 테이블의 캐시)에 없으면 TLB 미스가 발생, 이 경우 MMU는 페이지 테이블을 조회하여 해당 페이지가 메모리에 있는지 확인한다. 페이지 테이블의 유효-무효 비트를 검사하여 유효(valid)하면 메모리에 존재하는 페이지이며, 무효(invalid)하면 페이지 부재 트랩이 발생

    • 만약 TLB에 변환 정보가 있다면 MMU는 빠르게 물리 주소를 얻을 수 있다.
    • TLB 미스(TLB Miss) 발생 시 MMU는 페이지 테이블을 직접 조회해서 변환 정보를 찾음
    • 이때 페이지 테이블에 유효-무효 비트를 확인하여 페이지가 메모리에 있는지 검사한다.
  2. 페이지 부재 트랩 (Trap)

    유효-무효 비트가 0이라면 MMU는 페이지 부재(page fault) 트랩을 발생, 이때 CPU는 커널 모드(Kernel Mode)로 전환되며, 운영체제의 페이지 부재 처리 루틴이 호출, 운영체제는 해당 프로세스의 컨텍스트를 저장하고 어떤 페이지를 가져와야 하는지 확인한 후 적절한 처리 과정을 수행

    • 트랩은 예외의 한 종류로 하드웨어가 감지한 이벤트에 의해 운영체제로 제어권이 넘어가는 과정
    • 페이지 부재 트랩이 발생하면 사용자 모드에서 커널 모드로 전환되며 운영체제가 페이지를 처리하는 루틴을 실행
  3. 페이지 부재 처리 실행

    운영체제는 페이지 부재가 발생한 원인을 분석, 만약 프로세스가 허용되지 않은 메모리 영역을 참조하거나 읽기 전용 페이지에 쓰기를 시도했다면 운영체제는 프로세스를 강제종료(SIGSEGV, segmentation fault)한다. 반면, 올바른 요청이라면 물리 메모리에서 빈 프레임을 찾아 페이지를 적재할 준비를 한다.

    • 운영체제는 페이지 부재가 발생한 이유를 먼저 분석
      • 읽기 전용 페이지에 쓰기 요청이 있었는지?
      • 프로세스가 접근할 수 없는 영역을 참조했는지?
        • 예를 들어, 널포인터(0x0) 참조, 커널 전용 메모리 영역(0xFFFFFFF) 접근, 권한이 없는 메모리 페이지에 접근할 경우
      • 스택이나 힙 확장이 가능한 영역인지?
        • 스택은 보통 높은 메모리 주소에서 낮은 주소 방향으로 확장되고 힙은 낮은 주소에서 높은 주소 방향으로 확장되는데 스택 프레임이 증가하면서 새로운 페이지를 필요로 하는 경우 OS는 페이지 부재를 처리하여 새로운 페이지를 할당한다. 반면, 스택/힙의 확장 범위를 벗어난 접근이라면 접근 위반(Exception)으로 간주하고 프로세스를 종료한다.
    • 정상적인 요청이라면 페이지를 로드할 준비
  4. 페이지 교체 알고리즘 및 Page-In/Page-Out

    운영체제는 물리 메모리에 빈 프레임이 있는지 확인한 후, 만약 빈 프레임이 없다면 페이지 교체 알고리즘을 사용하여 기존 페이지 중 하나를 선택하여 교체, 선택된 페이지는 스왑 영역으로 이동(page-out)한 후, 새롭게 필요한 페이지를 물리 메모리로 적재(page-in)한다.

  5. 페이지 테이블 업데이트

    운영체제는 페이지가 정상적으로 적재되었음을 확인한 후, 페이지 테이블에서 해당 페이지의 프레임 번호를 업데이트하고 유효 비트를 1로 설정한다. 또한, TLB에 페이지 정보를 추가하여 빠른 접근을 가능하게 한다. 이후 프로세스를 Ready-Queue로 이동시켜 다시 실행할 준비를 한다.

    • 페이지 테이블에서 해당 프레임의 프레임 번호와 유효 비트를 1로 설정
  6. 프로세스 재시작

    페이지 부재 처리가 완료된 후 운영체제는 해당 프로세스를 Ready-Queue로 이동시킨 후 스케줄러가 프로세스에게 다시 CPU를 할당하면 PCB(Process Control Block)에서 저장된 레지스터 값과 프로그램 카운터(PC)를 복원하여 중단된 명령을 계속 실행한다.

    • CPU가 다른 프로세스를 실행 중이었다면 스케줄러가 페이지 부재가 발생한 프로세스에게 다시 CPU를 할당해야 한다.

프로세스가 재시작될 때 효율적인 메모리 관리는 시스템 성능에 매우 중요해요. 리눅스는 이를 위해 버디 시스템(Buddy System)이라는 메모리 관리 기법을 사용합니다.

버디 시스템

버디 시스템은 물리 메모리를 2의 지수승 크기로 관리하여 빠른 할당과 회수를 가능하게 합니다. 예를 들어, 프로세스가 재시작되어 추가 메모리가 필요할 때,

  1. 시스템은 요청된 크기와 가장 근접한 2의 지수승 크기의 블록을 찾습니다.
  2. 필요한 경우 큰 블록을 두 개의 동일한 크기(”버디”)로 분할
  3. 메모리가 해제될 때는 인접한 가용 블록과 병합하여 더 큰 블록을 생성

리눅스에서는 페이징 기법을 기반으로 하되, 스와핑과 버디 시스템을 보조적으로 사용하여 메모리를 효율적으로 관리합니다.


번외. 직접 하드웨어 제어시 참고할 GPIO 정보

라즈베리파이5 제원: 브로드컴 BCM2712 쿼드코어 Arm Cortex-A76 프로세서 (2.4GHz)

  • GPIO 레지스터 베이스 주소 = 0x7e200000
  • GPFSEL0 = GPIO 기능 선택 0
  • GPSET0 = GPIO 핀 출력 설정 0
  • GPCLR0 = GPIO 핀 출력 지우기 0
  • GPLEV0 = GPIO 핀 레벨 0