시스템 프로그래밍 시험 공부하면서 정리한 내용이다. 내용 갱신은 없을 예정이다.
개요
- 선형 주소 공간 : 2 ** BIT_PER_LONG byte, 32bit의 경우 4GB
- 0 ~ 3GB (PAGE_OFFSET) : Process Address Space
- 3G의 Process Address Space에 대해서 자세하게 다룬다.
Kernel Memory Allocation
- 관련 커널 함수 (이전 내용의 연속)
- alloc_pages()
- 버디 시스템에서 연속된 프레임 할당
- vmalloc()
- 불연속적인 메모리 영역 할당
- kmem_cache_alloc(), kmalloc()
- slab 할당자 이요. 특수한 타입, 혹은 일반적인 목적
- alloc_pages()
- KMA (Kernel Memory Allocation) 특징
- 커널은 OS에서 우선순위가 가장 높은 컴포넌트이다. 따라서 커널 메모리 할당은 지연되면 안됨
- 커널은 스스로를 믿어야한다.
- 에러 없음
- 프로그래밍 에러에 대한 어떤 보호도 넣지 않는다
- 커널코드에서 요청한 것은 무조건 신뢰하며 반드시 처리한다
User Memory Allocation
- 유저 모드 프로세스가 메모리 할당 요청하면…
- KMA에도 우선순위가 낮다 (예:
malloc()
)- 일반적인 규칙으로, 커널은 유저 모드 프로세스에서의 동적 메모리 할당의 지연실행을 시도한다.
- 유저 프로그램을 믿을 수 없기 때문에 커널은 유저 모드 프로세서에서 발생하는 모든 어드레싱 에러를 잡을 준비를 해야한다.
- KMA에도 우선순위가 낮다 (예:
- 유저 프로세스를 위한 메모리 할당의 특징
- 유저 모드 프로세스가 동적 메모리를 요청하면 추가적인 페이지 프레임을 얻지않는다.
- 대신, 새로운 범위의 선형 주소를 할당한다. 이 메모리는 프로세스 주소 공간의 일부가 된다
- 커널이 유저 프로세스를 믿지 못하기 때문에 물리 메모리가 아닌 Linear Address를 일단 할당한다. 물리 페이지는 나중에 처리
The Process’s Address Space
프로세스의 주소 공간
- 프로세스가 사용할수 있도록 허용된 모든 선형 주소 공간으로 구성
- 커널은 프로세스의 주소공간을 선형 주소의 구간을 붙이고 제거함으로써 동적으로 수정할 수 있다.
Memory Region (메모리 구역)
- 선형 주소의 시작점, 길이, 접근권한으로 규정된 선형 주소공간에서의 구간
- 효율성 문제로 시작 주소와 크기는 4KB의 배수
- 페이지 프레임의 크기가 4KB, N개의 페이지에 맞추려고
When Process Get New Memory Regions?
- 새로운 프로세스가 생성될 때
- 새로운 프로세스용으로 메모리 구역을 할당
fork()
- 완전히 다른 프로그램을 로딩할 때
exec()
계열 함수. execution context의 내용을 새로운 실행파일로 교체
- Memory-mapping file을 사용할 때
mmap()
시스템 콜을 사용해서 프로레스가 새로운 메모리 매핑 파일을 생성할 때mmap()
: 메모리 매핑 파일을 생성, 프로세스 주소 공간에 연결
- 유저 모드 스택에 데이터를 추가할 때
- 메모리 구역의 크기를 늘린다
- 다른 협력 프로세스와 데이터를 공유할 때
- IPC shared memory
- malloc()를 통해 프로세스의 동적 영역(heap)를 확장
- heap에 할당된 메모리 영역을 확장
Related System Call
- brk : heap
- execv : 새로운 실행 파일 로드하고 프로세스 주소공간 변경
- fork : 새로운 프로세스 생성하면서 새로운 주소 공간 생성
- mmap, mmap2, mremap : memory mapped
- shmat, shmdt : shared memory region
- etc…
Memory Descriptor
- mm_struct
- 프로세스 주소 공간과 관련된 정보
- task_struct의 mm에서 연결됨
struct vm_area_struct *mmap
: memory region을 linked list로 구성struct rb_root mm_rb
: memory region을 RB-tree로 구성
Memroy Regions
- Memory regions
- 연속적인 페이지 번호를 가지고 있는 페이지들의 집합으로 구성
- Memory region descriptor :
struct vm_area_struct
- 선형 주소 공간을 식별
vm_start
,vm_end
vm_mm
: mm_struct 가리킴
Adding/Removing Linear Address Interval
- 이미 존재하는 메모리 영역에 인접하게 같은 종류의 메모리 구역을 추가하는 경우
- 두개를 합쳐서 하나로
- 이미 존재하는 메모리 영역에 인접하게 다른 종류의 메모리 구역을 추가하는 경우
- 그냥 두개인 상태로 유지
- 기존의 메모리 영역에서 끝의 일부를 제거하는 경우
- 메모리 영역의 크기가 작아진다
- 기존의 메모리 영역에서 가운데 일부를 제거하는 경우
- 메모리 영역이 두개로 쪼개진다.
- 머리+가슴+배 - 가슴 = 머리+배
Handling Memroy Regions
- 커널은 메모리 구역을 찾는 함수를 자주 수행한다
- 대부분의 리눅스 프로세스는 몇개의 메모리 구역만을 사용한다
- 하지만 일부 큰 어플리케이션은 몇천개의 메모리 구역을 가질 수 있다.
- 비효율적이고 느린 성능이 될수 있다
- 많은 수의 메모리 구역을 다루는 리눅스의 접근법
- 프로세스가 많은 수의 메모리 구역을 가지면 리눅스는 디스크립터를 RB-Tree에 저장
- RB-Tree는 요소의 수가 적을때 효율적이지 않다.
- linked-list / RB-tree 모두 상황에 따라서 사용 (적으면 list, 많으면 RB)
- 성능향상을 목표로 추가 메모리를 사용해서라도 자료구조 2개 유지
- 2.4.9 까지는 AVL-tree 이용했음
- 메모리 구역 다루기
- 일반적으로 RB-Tree : 특정 주소를 포함하는 메모리 구역을 찾을때
- 일반적으로 linked-list : 전체 메모리 구역을 검색
- 메모리 구역 접근 권한
vm_area_struct
: vm_flags- 페이지와 연관되는 다른 플래스
- 각각의 페이지 테이블 엔트리를 위한 읽기/쓰기, present flag
- page descriptor를 위한 플래그
- 선형 주소 구역을 할당/해제 하는 함수
do_mmap()
: include/linux/mm.h- VM area를 생성하고 mapping 수행 (메모리 공간 늘림)
do_munmap()
: include/mmap.c- VM area를 해제하고 주소 공간을 축소
- 다른 함수
find_vma()
: 주어진 주소에 가장 가까운 메모리 영역 찾기find_vma_intersection()
: 주어진 주소 구간에 겹치는 메모리 영역 찾기get_unmapped_area()
: 자유 주소 구간 찾기insert_vm_struct()
: 메모리 디스크립터 리스트안에 메모리 구역 넣기
Page Fault Exception Handling
- Page Fault Exception
- Address Translate Hardware에서 발생됨
- 프로세스 주소 영역에는 포함되지만 아직 할당되지 않음 페이지를 참조할때 발생
do_page_fault()
이용해서 예외를 다룬다
- Address Translate Hardware에서 발생됨
do_page_fault()
- page fault ISR (interrupt service routine)
- 아키텍쳐 특화, arch/i386/fault.c
- 현재 프로세스의 메모리 영역에 대해 페이지 폴트가 발생한 선형 주소를 비교한다.
- 물리 페이지에서 페이지 프레임 찾기
- 없던 페이지를 로딩해서 집어넣기
- 페이지 테이블 갱신
- page fault ISR (interrupt service routine)
Linux Page Fault Handling : Overall Scheme
- 주소가 프로세스 주소 영역에 포함되는가? 예
- 메모리 구역의 접근 권한이 일치하는가?
- 예 : 합법적 접근, 새로운 페이지 프레임을 할당
- 아니오 : 불법 접근, SIGSEGV
- 예시 : 코드영역에 쓰기 시도
- 메모리 구역의 접근 권한이 일치하는가?
- 주소가 프로세스 주소 영역에 포함되는가? 아니오
- 유저 모드에서 예외가 발생했는가?
- 예 : 커널 버그, 프로세스 죽인다
- 아니오 : 불법접근. SIGSEGV
- 유저 모드에서 예외가 발생했는가?
Linux Page Fault Handling
- VM Area -> Read/Write 권한 확인 -> Page Fault 처리
- VM Area가 아닌 구역 읽기
- 가상 주소가 올바른가?
vm_area_struct
가 정의된 영역인가?- 그렇지 않으면 segmentation violation 시그널
- .text 쓰기
- 프로세스가 해당 영역에 읽기/쓰기 가능한가?
- 그렇지 않으면 protection violation 시그널
- .data 쓰기
- 조건 충족하니까 fault를 처리
do_page_fault()
- good_area
- 프로세스 주소 공간에 주소가 포함된다
- 쓰기 접근에서 예외 발생한 경우, 함수는 메모리 구역이 쓰기 가능한지 확인한다. 쓰기 구역이 아니면 goto bad_area
- 읽기/실행 접근에서 예외 발생시, 함수는 페이지가 이미 램에 존재하는지 확인한다.
- bad_area
- 프로세스 주소 공간에 주소가 포함되지 않는다
- 유저 모드에서 에러 발생시 SIGSEGV 를 현재 프로세스로 보낸다
- 커널 모드에서 예외 발생시
- 시스템콜 인자로 넘어온 유저 프로세스의 주소를 이용할때 발생
- 이 예외는 진짜 커널 버그 때문에 발생했다
Allocate a New Page Frame
handle_pte_fault()
- 프로세스를 위한 새로운 페이지 프레임을 어떻게 할당할지 결정
- 접근한 페이지가 present가 아닌 경우
- 그것이 어떤 페이지 프레임 안에도 저장되어 있지 않은 경우, 커널은 새로운 페이지 프레임을 할당하고 적절히 초기화
- Demand paging
- 접근한 페이지가 present이지만 읽기 전용인 경우
- 그것이 페이지 프레임에 저장되어 있는 경우, 커널은 새로운 페이지 프레밍을 할당하고 기존 프레임의 내용을 새로운 프레임에 복사
- Copy On Write
Demand Paging
- 원리
- 동적 메모리 할당 기술은 페이지 프레임 할당을 진짜로 접근할때까지 미루는 것으로 구성
- 프로세스가 RAM에 올라가지 않는 주소의 페이지에 접근할때까지 연기 (Page Fault exception 발생)
- 모든 주소가 사용되진 않는다 (지역성)
- 페이지 폴트 예외 처리하는 오버헤드 발생
- 동적 메모리 할당 기술은 페이지 프레임 할당을 진짜로 접근할때까지 미루는 것으로 구성
- 어드레싱된 페이지는 메인 메모리에 존재하지 않을 수 있다
do_no_page()
: pte 엔트리가 전부 0 일때- 프로세스가 페이지에 접근한 적이 없다
do_swap_page()
: pte 엔트리가 0이 아닐때- 프로세스가 페이지에 접근한 적이 있으나 페이지 내용이 일시적으로 디스크에 저장되었다
- swapped out to disk
Copy On Write
- 전통적인 유닉스에서는 fork()를 이용해서 새로운 프로세스를 만들었다
- 부모의 전체 주소 공간을 자식 프로세스의 주소 공간으로 복제 -> 비용이 비싸고 시간이 오래 걸린다
- 어떻게 실제 복사 과정을 미룰수 있는가?
- Copy On Write (
do_wp_page()
)- 페이지 프레임을 복사하는 대신 부모와 자식 프로세스는 페이지를 공유한다
- 쓰기가능 영역의 페이지를 읽기 전용으로 만든다.
- 프로세스가 쓰기 시도시 하드웨어에 의해 page fault 발생
- fault 핸들러는 COW를 인식하고 페이지를 복하한 다음에 쓰기 권한을 복구한다
- 최종 결과
- 복사과정은 진짜로 필요해질때까지 지연된다 (프로세스가 공유 페이지를 수정하려고 할때)
Creating a Process Address Space
- copy_mm()
- 프로세스 주소 공간을 생성
- 새로운 프로세스의모든 페이지 테이블과 메모리 디스크립터를 설정
- clone(), fork(), vfork(), …
- clone() + CLONE_VM = lightweight 프로세스 생성
- 프로세스 주소 공간을 생성
- CLONE_VM 설정시
tsk->mm = current->mm
같은 식으로 복사
Deleting a Process Address Space
- exit_mm()
- 프로세스가 갖고있는 주소 공간을 해제
Managing the Head
- Heap
- 프로세스의 동적 메모리 할당요청에 사용되는 특별한 메모리 구역
- start_brk, brk가 해당 구역의 시작과 끝을 표시
- C library
- malloc
- calloc(n, size)
- free
- brk
- heap의 크기 직접 변경
- heap 크기 줄이기 :
do_munmap()
->sys_brk()
- heap 크기 늘이기 :
do_mmap()
->sys_brk()
kswapd() : Kernel Swap Daemon
- 커널 쓰레드로 구현
kswapd()
: mm/vmscan.c- 주기적으로 깨어남
- 메모리가 부족할 경우 더 자주 깨어남
- 메모리가 부족한지 확인
- 사용되지 않은 페이지의 나이 계산
- 페이지를 inactive list로 이동
- dirty page를 디스크에 쓰기
- 페이지 swap out이 필요한 경우 수행
- Zone 자료 구조와 관련 (이전 내용 참고)
- pages_min : 도달시, kswapd가 깨어남
- pages_low : 도달시, 할당자는 kswapd()를 동기적 방법으로 수행
- pages_high : kswapd가 깨어나면 high만큼의 자유 페이지 프레임이 생길때까지 잠들지 않는다
Page Replacement
- 2개의 LRU List
- inactive_list
- 중요하다고 알고있지 않은 페이지 목록
- 파일 시스템에 의해 디스크에 기록되는 동안 dirty page는 몇 패스동안 inactive_list에 유지된다
- active_list
- 자주 참조된다고 알고있는 페이지 목록
- working set으로 정의됨
- 프로세스가 계속 참조
- inactive_list
- 새로운 페이지는 inactive_list의 머리에 추가됨
- 메모리가 부족해지면, active_list의 일부 페이지는 inactive_list의 머리에 들어가고 inactive_list의 꼬리에서 일부 페이지가 해제된다.
- 감지된 working set은 active_list로 들어간다
Summary : Process Memory
- Process Virtual Address Space는 Memory Area로 표현된다.
- 물리 메모리는 kswapd에 의해 swap out 당해 Backing Store(hard-disk) 에 들어갈수 있다
- Page Fault에 의해 Backing Store의 내용이 물리 메모리로 채워진다. 이때 Page Table을 이용한다.