프로세스 가상메모리
가상 메모리의 개념
1.가상 메모리의 기본 개념
- 가상 메모리는 프로그램들이 물리적 메모리를 직접 사용하지 않고, 간접적으로 사용하는 메모리 관리 기법입니다.
- 물리 메모리는 여러 개의 페이지 프레임(보통 4KB 크기)으로 나눠지며, 각 프로그램은 가상 주소를 통해 물리 메모리에 접근합니다.
2.물리 페이지와 페이지 프레임
- 물리 페이지(Physical Page)와 페이지 프레임(Page Frame)은 동일한 개념으로, 물리 메모리의 작은 조각을 의미합니다.
- 물리 페이지는 하드웨어 관점에서 나눠진 메모리 조각이며, 리눅스 커널이 이들을 관리합니다.
3.가상 주소와 물리 주소의 매핑
- 프로그램들은 가상 주소를 사용하며, 리눅스 커널은 가상 주소를 물리 주소에 매핑합니다.
- 매핑 정보는 페이지 테이블(Page Table)에 저장됩니다.
- 초기 페이지 테이블은 비어 있으며, 프로그램이 메모리를 사용할 때 페이지 폴트(Page Fault)예외가 발생하여 필요한 페이지를 물리 메모리에 할당하고 매핑을 업데이트합니다.
4.페이지 테이블과 태스크 구조체
- 페이지 테이블: 가상 주소와 물리 주소 간의 매핑 정보를 저장하는 테이블입니다.
- mm_struct: 각 프로세스의 가상 메모리 사용 정보 등을 기록한 구조체이고 여러개의 vma 들로 구성됩니다.
- 페이지 테이블과 가상 메모리 사용 정보는 커널 전용 메모리에 저장되어 관리됩니다.
5.커널 전용 메모리
- 커널은 전체 메모리의 일부를 전용으로 사용하며, 나머지 메모리 조각들을 관리하기 위해서 커널 전용 메모리에 관리정보들을 기록합니다.
즉, 가상 메모리는 프로그램이 물리 메모리를 직접 다루지 않고, 가상 주소를 통해 간접적으로 접근하도록 하여 효율적인 메모리 관리를 가능하게 합니다. 각각의 프로세스들은 각자만의 페이지 테이블을 통해 가상 주소와 물리 주소의 매핑을 관리하고, mm_struct 통해서 프로세스 마다 세부적으로 메모리를 얼마나 사용하는지 (스택, 힙 등) 관리합니다. 처음에는 페이지 테이블상에 가상주소와 물리주소 매핑정보가 없고 빈테이블로 시작하지만 메모리 사용하는 만큼만 연결하여 사용하게 됩니다.
리눅스에서 프로세스 메모리 확인
-리눅스에서는 프로세스 메모리를 확인하고 관리하는 방법이 여러 가지가 있습니다. 이를 통해 시스템의 효율성을 높이고 문제를 해결할 수 있습니다. 다음은 프로세스 메모리를 확인하는 방법에 대한 요약입니다.
1. `/proc` 파일 시스템
- 리눅스에서 `/proc` 파일 시스템을 통해 시스템 및 프로세스 관련 다양한 정보를 확인할 수 있습니다.
- 각 프로세스는 `/proc` 디렉터리 아래에 프로세스 ID(PID)로 된 디렉터리를 가지며, 이 디렉터리 내에는 해당 프로세스의 상태, 메모리 사용량 등을 포함한 여러 파일이 존재합니다.
2. 프로세스 메모리 확인
- 프로세스 메모리 사용량을 확인하기 위해 `/proc/[PID]/status`, `/proc/[PID]/maps`, `/proc/[PID]/smaps` 등의 파일을 사용할 수 있습니다.
예시: `bash` 셀 프로세스의 메모리 확인
- 현재 사용 중인 `bash` 셀 프로세스의 PID를 확인합니다.
echo $$
- 해당 PID를 사용하여 `/proc/[PID]` 디렉터리의 파일들을 확인합니다.
cat /proc/[PID]/status
여기서 `VmSize`, `VmRSS`, `VmData` 등의 항목을 통해 프로세스의 메모리 사용량을 확인할 수 있습니다.
메모리 매핑 정보 확인
- `/proc/[PID]/maps` 파일을 통해 프로세스의 메모리 매핑 정보를 확인할 수 있습니다.
cat /proc/[PID]/maps
이 파일은 프로세스의 메모리 영역(예: 힙, 스택, 텍스트 등)에 대한 정보를 제공합니다.
- `/proc/[PID]/smaps` 파일을 통해 메모리 매핑의 세부 정보를 확인할 수 있습니다.
cat /proc/[PID]/smaps
3. 명령어 사용
- `ps` 명령어를 사용하여 프로세스의 메모리 사용량을 요약하여 확인할 수 있습니다.
ps -eo pid,comm,vsz,rss | grep [PID]
여기서 `RSS`(Resident Set Size)와 `VSZ`(Virtual Memory Size)를 확인할 수 있습니다.
스택(Stack)과 힙(Heap) 메모리 분석
- 스택과 힙 메모리는 프로그램 실행 시 메모리를 할당하고 관리하는 두 가지 주요 방식입니다. 스택과 힙은 각기 다른 특성과 사용 용도를 가지고 있으며, 디버깅 도구를 통해 상세히 분석할 수 있습니다. 다음은 스택과 힙 메모리의 개념 및 분석 방법에 대한 요약입니다.
1. 스택(Stack) 메모리
- 스택 메모리는 함수 호출 시 자동으로 할당되고 함수가 종료되면 자동으로 해제되는 메모리입니다.
- 주로 지역 변수와 함수 호출 정보를 저장하는 데 사용됩니다.
- 스택은 LIFO(Last In, First Out) 구조로 관리되며, 메모리 할당과 해제가 빠릅니다.
스택 메모리 분석
- 스택 메모리는 함수 호출 시 자동으로 할당되며, 지역 변수들이 저장됩니다.
- 예를 들어, `int a`와 같은 변수(4바이트)는 스택에 할당됩니다.
- 64비트 시스템에서는 포인터 변수의 크기가 8바이트입니다.
- 스택 메모리 할당은 16바이트 단위로 이루어지는 경우가 많습니다. 이는 하드웨어 캐시 라인 크기와 성능 최적화를 위해서입니다.
2. 힙(Heap) 메모리
- 힙 메모리는 동적 메모리 할당 시 사용됩니다. 프로그래머가 명시적으로 할당하고 해제해야 합니다.
- 주로 `malloc`이나 `new` 같은 함수로 할당하며, `free`나 `delete`로 해제합니다.
힙 메모리 분석
- 힙 메모리는 `malloc` 함수 등을 통해 동적으로 할당됩니다.
- 예를 들어, `char *buffer = malloc(1024)`는 1KB의 메모리를 힙에서 할당합니다.
- 할당된 메모리는 힙에 저장되고, 해당 메모리의 주소가 변수에 저장됩니다.
디버깅을 통한 분석
디버깅 도구를 사용하여 스택과 힙 메모리를 분석할 수 있습니다. 다음은 gdb를 이용한 디버깅 예시입니다.
예제 코드
#include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int a = 1; // 스택에 할당 char *buffer = malloc(1024); // 힙에 1KB 할당 strcpy(buffer, "Hello, World!"); // 힙 메모리에 문자열 저장 printf("%s\n", buffer); // 힙 메모리의 문자열 출력 free(buffer); // 힙 메모리 해제 return 0; }
gdb를 통한 분석 단계
1. 프로그램 컴파일
gcc -g -o hello hello.c
2. gdb 실행 및 브레이크 포인트 설정
gdb -q ./hello (gdb) break main (gdb) run
3. 변수의 메모리 할당 확인
(gdb) disassemble (gdb) ni 5 (gdb) x/gx $rsp
4. 스택 메모리 확인
- `a` 변수의 숫자값과 `buf` 포인터 변수에 저장된 주소값을 확인합니다.
5. 힙 메모리 확인
- `buf` 변수에 저장된 힙 메모리 주소와 해당 메모리의 내용(문자열)을 확인합니다.
(gdb) x/s [힙 메모리 주소]
다음과 같은 내용의 리얼리눅스 추천 강의는 시스템핵심정리 입니다.
https://reallinux.co.kr/course/se_system