15. 프로세스 주소 공간
- 커널은 사용자 공간 프로세스의 메모리도 관리해야 하며 이를 ‘프로세스 주소 공간’이라고 부른다.
- 프로세스는 유효한 메모리 영역에만 접근해야 하며, 이를 어길시 segment fault를 만날 것이다.
15.1 메모리 서술자 구조체 mm_struct
-
<linux/mm_types.h>
에는mm_struct
라는 메모리 서술자 구조체가 정의돼있다.mm_users
: 이 주소 공간을 사용하는 프로세스의 개수를 의미한다.mm_count
: 이 구조체의 주 참조 횟수다.- 9개 스레드가 주소 공간을 공유한다면?
mm_users == 9, mm_count == 1
mm_users == 0
-> mm_count를 하나 감소시킨다.mm_count == 0
-> 이 주소 공간을 참조하는 놈이 하나도 없으니 메모리를 해제한다.
- 9개 스레드가 주소 공간을 공유한다면?
- mmap, mm_rb: 동일한 메모리 영역을 전자는 연결리스트로, 후자는 레드-블랙 트리로 나타낸 것이다.
- 왜 같은 대상을 중복 표현해서 메모리를 낭비하는 걸까?
- 메모리 낭비는 있겠지만, 얻을 수 있는 이점이 있기 때문이다.
- 전후 관계를 파악하거나 모든 항목을 탐색할 때는 연결리스트가 효율적이다.
- 특정 항목을 탐색할 때는 레드-블랙 트리가 효율적이다.
- 이런 방식으로 같은 데이터를 두 가지 다른 접근 방식으로 사용하는 것을 ‘스레드 트리’라고 부른다.
-
이미 3장에서
task_struct
를 배울 때 mm 멤버변수로 이 구조체를 봤었다.- 복습하자면,
current->mm
은 현재 프로세스의 메모리 서술자를 뜻하며, fork()
→copy_mm()
함수가 부모 프로세스의 메모리 서술자를 자식 프로세스로 복사하며,- 복사할 때 12.4절에서 배운 ‘슬랩 캐시’를 이용해
mm_cachep
에서mm_struct
구조체를 할당한다. - 만일 만드는게 스레드라면, 생성된 스레드의 메모리 서술자는 부모의 mm을 가리킬 것이다.
- 그리고 커널 스레드라면, 당연히 프로세스 주소 공간이 없으므로 mm == NULL이다.
- (+ 추가내용: 커널 스레드가 종종 프로세스 주소 공간의 페이지 테이블 일부 데이터가 필요한 경우가 있다. 메모리 서술자의 mm == NULL일 때, active_mm 항목은 이전 프로세스의 메모리 서술자가 가리키던 곳으로 갱신된다. 따라서 커널 스레드는 이전 프로세스의 페이지 테이블을 필요할 때 사용할 수 있다.)
- 복습하자면,
15.2 가상 메모리 영역 구조체 vm_area_struct
- 리눅스 커널에서 ‘가상 메모리 영역’은 VMA라고 줄여 부르며
<linux/mm_type.h>
의vm_area_struct
구조체로 메모리 영역을 표현한다.
- 주요 멤버 변수를 살펴보면 아래와 같다.
vm_start
,vm_end
: 가상 메모리 영역의 시작주소와 마지막 주소를 의미하므로 이 둘의 차이가 메모리 영역의 바이트 길이가 된다. 다른 메모리 영역끼리는 중첩될 수 없다.vm_mm
: VMA 별로 고유한 mm_struct를 보유한다. 동일 파일을 별도의 프로세스들이 각자의 주소 공간에 할당할 경우 각자의 vm_area_struct를 통해 메모리 공간을 식별하게 된다.vm_flags
: 메모리 영역 내 페이지에 대한 정보(읽기, 쓰기, 실행 권한 정보 등)를 제공한다.vm_ops
: 메모리 영역을 조작하기 위해 커널이 호출할 수 있는 동작 구조체 vm_operations_struct를 가리킨다. (13절 VFS를 설명할 때 언급했던 ‘동작 객체’ 구조체와 비슷한 개념이다.)
15.3. 실제 메모리 영역 살펴보기
- 간단한 프로그램을 만들고, ‘/proc’ 파일시스템과 pmap 유틸리티를 통해 특정 프로세스의 주소 공간과 메모리 영역을 살펴보자.
-
/proc/<pid>/maps
파일은 프로세스 주소 공간의 메모리 영역을 출력해준다. -
pmap 유틸리티를 사용하면 위 정보를 조금 더 가독성 있게 표현해준다.
-
지금까지 다룬 구조체의 구조를 깔끔하게 도식화한 그림이다.
-
task_struct
의 mm은 각 프로세스의 메모리 서술자인mm_struct
이다. -
mm_struct
의 mmap은 가상 메모리 영역vm_area_struct
을 표현하는 연결리스트다. -
vm_area_struct
는 프로세스의 실제 메모리 영역(.txt, .data 등)을 나타낸다.
- 알다시피, 커널과 애플리케이션은 가상 주소를 사용하지만, 프로세서는 물리 주소를 사용한다.
- 따라서 프로세서와 애플리케이션이 서로 상호작용하기 위해서는 페이지 테이블을 통해 변환작업이 필요하다.
- 리눅스 커널은 PGD(Global), PMD(Middle), PTE 세 단계의 페이지 테이블을 사용한다.
- 페이지 테이블 구조는 아키텍처에 따라 상당히 다르며
<asm/page.h>
에 정의돼있다.
참고