memory mapping

전두엽힘주기·2025년 4월 28일

Computer System

목록 보기
10/13

Memory Mapping

Memory Mapping(메모리 매핑) 이란,
VM(가상 메모리) 영역을 특정 디스크 객체와 연결하여 초기화하는 과정을 의미한다.

메모리 매핑은 프로세스 주소 공간에 파일 내용을 직접 대응시키는 것으로,
이 덕분에 파일의 내용을 메모리에 명시적으로 read() 없이도 직접 접근할 수 있다.

메모리 매핑의 종류 (Backing Source)

메모리 매핑은 어떤 디스크 객체로부터 초기 데이터(page)를 채울지에 따라 다음 두 가지로 나뉜다:

종류

  • Regular file-backed mapping: 디스크에 있는 정규 파일(예: 실행 파일, 데이터 파일)을 메모리에 매핑. 초기 페이지의 내용은 파일의 일부로부터 읽어온다.
  • Anonymous mapping: 디스크 파일이 없는 경우. 즉, 매핑할 초기 데이터가 없다. 이 경우 첫 번째 접근(페이지 폴트) 때, 0으로 채워진 물리 페이지가 새로 할당된다. (Demand Zero Page)

Anonymous Mapping (Demand Zero Page)
• 익명 매핑(anonymous mapping)은 특별한 파일 없이 메모리만 요청하는 경우이다.
• 이 경우 초기 페이지는 디스크로부터 채워지지 않는다.
• 사용자가 처음 그 페이지를 읽거나 쓰려고 하면:
• 페이지 폴트(page fault)가 발생하고
• 커널이 물리 메모리 한 페이지를 할당하고
• 해당 페이지를 0으로 초기화한다.
• 이 과정을 통해 메모리는 “깨끗한 0으로 채워진 상태”로 사용자에게 제공된다.
→ Demand Zero Memory

Dirty Pages (더럽혀진 페이지)
• 만약 이 새로 생성된 페이지에 쓰기(write) 가 발생하면,
• 페이지는 dirty(더럽혀짐) 상태가 된다.
• “Dirty”란 페이지 내용이 “초기 상태”와 달라졌음을 의미한다.
• dirty page는 메모리와 디스크 간에 다음과 같이 처리된다:
• Swap 공간(특수 스왑 파일)으로 복사되거나
• 메모리 안에서 유지되며 필요 시 교체(swap out)된다.

•	Memory mapping은 디스크 파일 또는 익명 메모리를 VM에 연결하는 것.
•	파일 기반 매핑: 초기 내용은 디스크 파일에서 가져온다.
•	익명 매핑: 초기 내용이 없으며, 페이지 폴트 발생 시 0으로 초기화된 페이지를 할당한다.
•	쓰기(dirty)한 페이지는 이후 스왑 파일을 통해 디스크와 메모리 간 복사된다.


[ Regular file mapping ]
프로세스 메모리 ↔ 디스크 파일 일부

[ Anonymous mapping ]
프로세스 메모리 ↔ (처음엔 아무것도 없음) → 최초 접근 시 0으로 초기화된 페이지 할당

[ Dirty page ]
수정된 페이지는 메모리 ↔ 스왑 공간에 저장

추가로,
• mmap() 시스템 콜이 이 과정을 트리거한다.
• 특히 공유 라이브러리나 실행파일 로딩에서 정규 파일 매핑을 사용하고,
• malloc 내부에서 확장할 때는 보통 익명 매핑(MAP_ANONYMOUS)을 쓴다.

More about Demand Zero Memory

Demand Zero Memory란,
프로그램이 메모리를 요청했을 때 커널이 실제 물리 메모리를 바로 할당하지 않고,
필요한 순간(처음 접근할 때)에 진짜 메모리 페이지를 할당하고,
그 페이지를 0으로 초기화한 다음에 프로그램에 넘겨주는 방식이다.

이 방식은 리눅스의 “게으른(lazy)” 메모리 관리 전략 중 하나로,
메모리 효율성과 초기화 비용 최적화를 동시에 노린다.

동작 과정
1. 사용자 프로그램이 메모리를 요청한다. (sbrk, mmap, malloc 내부적으로)
2. 커널은 “이 영역이 프로그램에 할당되었다”는 가상 메모리(VM) 테이블만 수정한다.
→ 아직 실제 물리 메모리는 할당하지 않는다.
→ 이 영역은 ‘예약(reserved)’ 상태지만, 물리 메모리 없이 존재한다.
3. 프로그램이 처음으로 해당 메모리 영역에 접근(읽거나 쓰기) 하려 한다.
4. CPU는 페이지 폴트(page fault) 예외를 발생시킨다.
5. 커널은 이 페이지 폴트 핸들러를 통해,
• 실제 물리 메모리를 새로 할당하고
• 그 메모리를 0으로 초기화한 뒤
• 접근하려던 명령어를 다시 실행시킨다.
6. 이제부터 이 페이지는 정상적으로 사용 가능해진다.

(간단버전)
1.	“나 메모리 필요해요!” 라고 요청한다.
2.	커널은 그냥 “여기 자리 예약해줄게!” 하고 아무것도 안 한다.
3.	처음 그 자리에 뭔가 쓰려고 하면,
4.	컴퓨터가 “어, 진짜 쓰려 하네?” 하고
5.	그때 깨끗한 종이를 꺼내서 준다.
6.	이제 편하게 글씨를 쓸 수 있다!

특징

• 게으른 초기화(lazy initialization): 필요할 때까지 물리 메모리 할당을 미룸 → 메모리 낭비를 줄임.
• 보안 강화(security): 초기화되지 않은 이전 데이터가 노출되지 않도록, 무조건 0으로 채운다.
• 성능 최적화(performance): 필요 없는 페이지까지 미리 초기화하는 시간을 줄여 프로그램 시작 속도가 빠르다.
• 메모리 절약(memory efficiency): 요청은 많지만 실제로 쓰이지 않는 메모리 공간을 실제로는 점유하지 않음.

어디서 사용될까?

• malloc() 으로 큰 메모리 할당할 때 (calloc()이 아닌 경우에도 내부적으로 초기화는 lazy하게 이루어질 수 있음)
• brk(), sbrk() 로 힙(Heap) 영역을 확장할 때
• mmap() 으로 익명 매핑(anonymous mapping)할 때 (MAP_ANONYMOUS)
• 프로그램 시작 시 .bss 섹션 (초기화되지 않은 전역변수 공간)
→ 이 공간도 실제 접근할 때까진 페이지 폴트를 통해 물리 메모리를 할당하고 0으로 채운다.


시스템 콜
brk() / sbrk(): 힙 영역을 조정. 하지만 진짜 메모리 할당은 페이지 폴트로 발생.
mmap(): 메모리 매핑. 익명 매핑일 때 demand-zero로 동작할 수 있다.
page fault handler: 처음 접근 시 커널이 물리 메모리를 할당하고 0으로 초기화해주는 곳.

• 현대 리눅스 커널에서는, Transparent Huge Pages (THP) 기술과 결합해서 큰 페이지 단위(예: 2MB)로 demand-zero를 처리하기도 한다.
• demand-zero는 메모리를 “가상으로 많이 할당”해도 실제 물리 메모리 사용량은 적게 유지할 수 있게 한다.
예를 들어, 1GB를 malloc 해도 실제로는 몇 KB만 사용하는 경우가 가능하다.

Demand Zero Memory란, “필요할 때까지 물리 메모리 할당을 미루고, 최초 접근 시 0으로 초기화하는” 메모리 관리 기법이다.

0개의 댓글