메모리 관리는 프로세스가 효율적으로 메모리를 사용할 수 있도록 지원합니다. 리눅스 메모리 관리 서브시스템의 주요 구성 요소를 살펴보겠습니다.
1. Linux Memory Management Subsystems
리눅스의 메모리 관리 서브시스템은 서로 긴밀하게 연관되어 있습니다.

가상 주소 공간 관리
- task_struct
- 프로세스를 나타내며 메모리 관리에 관한 정보를 포함
- mm (Memory Management)
task_struct
의 일부로, 메모리 관련 작업을 처리
- vmarea
- 프로세스의 가상 메모리 섹션을 나타냄
- text : 실행 가능한 코드가 포함
- data : 초기화된 전역 및 정적 변수가 저장
- heap : 동적 메모리 할당에 사용
- stack : 함수 호출 스택을 관리
주소 변환
- pgd (Page Global Directory), pmd (Page Middle Directory), pte (Page Table Entry)
- 가상 주소를 물리적 주소로 변환하는 다단계 페이지 테이블의 구조
물리적 메모리 관리
- 사용된 페이지
- 페이지 캐시 또는 스왑 캐시에 존재
- 익명(anon) 또는 없음(none)
- 활성 리스트 또는 비활성 리스트, 슬랩 캐시의 일부
프리 페이지 관리
수요 페이징 및 스와핑
- 파일 맵(File-map) 및 스왑 맵(Swap-map)
프로세스 가상 주소 공간 관리
- 프로세스에 대해 고유한 가상 주소 공간을 제공
가상주소 공간 영역
가상 주소 공간 관리는 vm_area_struct
와 같은 구조체를 통해 프로세스의 메모리 접근을 관리
주소 변환 계층
- 가상 주소를 물리 주소로 변환하는 주소 변환 계층을 제공
- 페이지 테이블을 사용하여 가상 주소와 물리 주소 간의 매핑을 관리
- 페이지 테이블은 페이지 폴트가 발생할 경우 커널은 페이지 테이블을 업데이트하여 필요한 페이지를 메모리에 로드
요구 페이징 및 페이지 교체
요구페이징
- 요구 페이징(demand paging) 기법을 사용하여 메모리 사용을 최적화
- 프로세스가 실제로 필요로 할 때만 페이지를 메모리에 로드하는 방식
- 페이지가 메모리에 존재하지 않을 경우 페이지 폴트가 발생하며 커널은 페이지 폴트 핸들러를 통해 해당 페이지를 디스크에서 메모리로 로드
페이지 교체 알고리즘
- 메모리가 부족할 때 어떤 페이지를 디스크로 퇴거할지를 결정
- LRU(Least Recently Used)와 같은 알고리즘을 사용하여 가장 오랫동안 사용되지 않은 페이지를 선택하여 교체
물리 메모리 조직 및 처리
- 물리 메모리를 효율적으로 관리하기 위해 다양한 기법을 사용
- 물리 메모리는 페이지 프레임으로 나뉘며 각 페이지 프레임은 페이지 테이블을 통해 가상 주소와 매핑
- 메모리 할당 및 해제를 관리하며 메모리 조각화 문제를 최소화하기 위해 Buddy System과 같은 메모리 할당 기법을 사용
2. TLB(Translation Lookaside Buffer)
- 주소 변환을 빠르게 수행하기 위한 캐시
- 최근에 사용된 페이지 테이블 엔트리를 저장하여 페이지 테이블에 접근하는 시간감소
- TLB의 크기는 보통 16~256개의 엔트리를 가지며 LRU(Least Recently Used) 알고리즘을 사용하여 교체 정책을 결정
- TLB의 효율적인 사용은 메모리 접근 성능을 크게 향상
3. 대규모 페이지 지원(Huge Pages)
- 대규모 페이지 기능을 지원하여 메모리 관리의 효율성 증가
- 일반 페이지보다 큰 크기를 가지며 페이지 테이블의 크기를 줄이고 페이지 폴트 발생 빈도를 낮추어 성능을 향상
- 데이터베이스와 같은 메모리 집약적인 애플리케이션에서 유용하게 사용
대규모 페이지 사용 방법
echo 1 > /proc/sys/vm/nr_hugepages
4. NUMA 아키텍처에서의 메모리 관리
- NUMA 아키텍처는 여러 프로세서가 각각의 로컬 메모리에 접근할 수 있는 구조
- 프로세스가 로컬 메모리에 접근할 때 성능을 최적화
- 메모리 접근 지연을 줄이고 멀티코어 시스템에서의 성능을 향상시키는 데 기여
5. 시스템 호출 예시
- mmap
-
파일이나 장치를 메모리에 매핑하는 데 사용
-
호출은 메모리 매핑을 통해 파일의 내용을 메모리에서 직접 접근
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("example.txt", O_RDONLY);
size_t length = 4096;
char *map = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
if (map == MAP_FAILED) {
perror("mmap");
return 1;
}
munmap(map, length);
close(fd);
return 0;
}
- brk 및 sbrk
6. 메모리 관리와 관련된 일반적인 문제점 및 디버깅 팁
문제점
- 메모리 누수
- 할당된 메모리를 해제하지 않으면 메모리 누수가 발생
- 모든 동적 메모리 할당 후에는 반드시 해제를 수행 필요
- 페이지 폴트
- 페이지 폴트가 자주 발생하면 성능이 저하
- 메모리 접근 패턴을 최적화하거나 대규모 페이지를 사용이 필요
디버깅 팁
- valgrind
- 메모리 누수를 검사하고, 메모리 오류를 찾는 데 유용한 도구
- /proc/PID/maps
- 특정 프로세스의 메모리 맵을 확인하여 메모리 사용 현황을 파악가능
7. 결론
리눅스 커널의 메모리 관리 서브시스템은 프로세스가 메모리를 효율적으로 관리하고 사용할 수 있도록 돕는 중요한 기능입니다. 프로세스 가상 주소 공간 관리, 주소 변환 계층, 요구 페이징 및 페이지 교체, 물리 메모리 조직 및 처리, TLB, 대규모 페이지 지원, NUMA 아키텍처에서의 메모리 관리 등 다양한 구성 요소가 상호작용하여 메모리 관리의 효율성을 높입니다.