본문 바로가기
CS 지식/시스템 프로그래밍

[C언어] 메모리 매핑 입출력(Memory Mapped I/O) 관련 시스템 콜(System call)

by 코딩하는 동현 2025. 3. 2.

Memory Mapped I/O (mmap)

Memory Mapped I/O는 파일 디스크립터(fd)를 직접 사용하는 대신, 파일을 메모리에 매핑하여 접근하는 방식이다. 이를 통해 시스템 콜을 최소화하고, 데이터를 빠르게 읽고 쓸 수 있다.

mmap() - 파일을 메모리에 매핑

void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);

매개변수 설명

  • addr : 매핑할 메모리 주소를 커널에게 '제안' (보통 0 입력하여 자동 지정)
  • len : 매핑할 크기 (바이트 단위)
  • prot : 메모리 보호 설정 (비트 OR 연산 사용 가능)
    • PROT_READ : 읽기 가능
    • PROT_WRITE : 쓰기 가능
    • PROT_EXEC : 실행 가능
  • flags : 매핑 속성을 설정
    • MAP_PRIVATE : 다른 프로세스와 공유하지 않음 (Copy-on-Write)
    • MAP_SHARED : 같은 파일을 매핑한 다른 프로세스와 공유
    • MAP_FIXED : 특정 주소에 매핑 강제
  • fd : 매핑할 파일의 파일 디스크립터
  • offset : 파일에서 매핑을 시작할 위치 (페이지 크기 단위로 정렬 필요, 예: 4KB)

반환값 : 성공 시 매핑된 메모리 주소, 실패 시 MAP_FAILED

munmap() - 메모리 매핑 해제

int munmap(void *addr, size_t len);
  • addr : 매핑을 해제할 메모리 주소
  • len : 해제할 메모리 크기
  • 반환값 : 성공 시 0, 실패 시 -1

Reference Count (참조 카운트)

파일을 메모리에 매핑하면 Reference Count가 증가하며, 파일 디스크립터(fd)를 닫아도 매핑된 메모리는 유지된다.

예제: fd를 닫아도 메모리에서 파일 접근 가능

int main(int argc, char *argv[]){
    struct stat sb;
    char *p;
    int fd;
    
    if(argc < 2){
        printf("Usage: %s <pathname>\n", argv[0]);
        exit(1);
    }
    
    fd = open(argv[1], O_RDONLY);
    if(fd == -1){
        perror("open");
        exit(1);
    }
    
    if(fstat(fd, &sb) == -1){
        perror("fstat");
        exit(1);
    }
    
    if(!S_ISREG(sb.st_mode)){
        printf("Not a file\n");
        exit(1);
    }
    
    p = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
    if(p == MAP_FAILED){
        perror("mmap");
        exit(1);
    }
    
    close(fd); // 파일 디스크립터를 닫아도 매핑된 메모리는 유지됨
    
    for(off_t len = 0; len < sb.st_size; len++){
        putchar(p[len]);
    }
    
    munmap(p, sb.st_size);
    return 0;
}

실행 예시

./a.out file1.txt
konkuk university

Reference Count가 감소하는 경우

  • munmap() 호출 시
  • 프로세스가 종료될 때

mmap vs Unix IO

장점

  • 낮은 오버헤드: read(), write()와 달리 커널과의 컨텍스트 스위칭 없이 메모리에 직접 접근 가능
  • 공유하기 쉬움: MAP_SHARED 옵션을 사용하면 여러 프로세스가 동일한 메모리를 공유 가능
  • Seek 속도가 빠름: lseek() 없이 메모리 포인터만 조정하면 특정 위치로 이동 가능

단점

  • 공간 낭비 : 페이지 크기(예: 4KB) 단위로만 매핑 가능하므로, 6KB 매핑 시 8KB 사용
  • 매핑 크기 제한: 프로세스의 가상 메모리 공간 내에서만 매핑 가능
  • 매핑 시 큰 오버헤드: 매핑 설정 시 시스템 자원이 소모되며, 작은 파일에 대해 반복적인 매핑은 비효율적

Memory Mapped I/O는 높은 성능과 효율성을 제공하지만, 매핑 크기와 오버헤드 관리에 신경 써야 한다. 적절한 상황에서 mmap()을 활용하면 시스템 성능을 크게 향상시킬 수 있다.

반응형

댓글