OS이야기
프로세스 주소영역
НooпeУ
2011. 10. 25. 12:32
리눅스는 가상메모리를 사용하는 운영체제이므로, 시스템상에 있는 프로세스의 메모리 역시 가상적으로 처리된다.
즉, 각각의 프로세스에게는 자신이 마치 시스템의 모든 메모리를 혼자서 사용하는 것처럼 보인다.
(히히, 다 내꺼임<- 멍청이)
커널이 어떻게 프로세스의 메모리를 관리하는지 살펴보장
프로세스의 주소공간은 각 프로세스에 제공되는 선형주소범위와 이 주소공간에서 프로세스가 사용할 수 있는 실제공간으로 나뉜다.
프로세스는 유효한 영역내에 있는 메모리 주소에만 접근할 수 있다. 더욱이 이러한 메모리읽기전용이나 실행불가 등으로 표시될있다. 만일 프로세스가 유요하지 않은 영역의 메모리 주소를 접근하려하거나 유효한 영역을 비정상적인 방법으로 접근할 경우, "segment fault"가 뜬다.
메모리영역은 다음과 같은 것들을 포함할 수 있다.
- 텍스트 섹션 : 실행파일의 코드에 대한 메모리맵
- 데이터 섹션 : 실행파일의 초기화된 전역변수에 대한 메모리맵
- bss 섹션 : 초기화되지 않은 전역변수를 포함하는 제로페이지(모두 0으로 초기화된 페이지)에 대한 메모리 맵
- 프로세스의 유저 공간 스택에 사용되는 제로페이지에 대한 메모리맵<- 유저공간의 스택임
- 프로세스 주소공간의 로드된 C라이브러리나 다이나믹 링커와 같은 공유 라이브러리를 위한 추가적인 텍스트/데이 터/bsstprtus
- 메모리 매핑된 파일들
- 공유 메모리 세그먼트
- malloc()에 생성된 익명의 메모리 매핑
메모리 서술자
- 커널은 프로세스의 주소공간을 메모리 서술자라는 자료구조로 표현한다. 이 구조체는 프로세스의 주소공간과 관련된 모든 정보를 포함하며
<linux/sched.h>에 정의돼있는 struct mm_struct으로 표현된다.
(2.6 이후에는 include/mm_types.h로 이동됨)
http://lxr.linux.no/linux+v3.1/include/linux/mm_types.h#L253
mm_users는 해당 주소공간을 사용하는 프로세스의 개수를 나타냄. 예를 들어 2개의 스레드가 주소공간을 공유한다며 mm_users는 2가 된다. mm_count 필드는 mm_struct에 대한 주 참조 카운터이다.All mm_users equate to one increment of mm_count.-> 무슨뜻이지? <참고 : http://www.iamroot.org/xe/?document_srl=42756>
또한 오직 mm_users가 0으로 될 때만(두 스레드가 종료되었을 때 ) mm_count가 감소한다. 결국 mm_count(mm_users아님???)가 0이되면 더 이상 mm_struct에 대한 참조가 없는 것이 되며, 이 구조체는 해제된다.
즉, 각각의 프로세스에게는 자신이 마치 시스템의 모든 메모리를 혼자서 사용하는 것처럼 보인다.
(히히, 다 내꺼임<- 멍청이)
커널이 어떻게 프로세스의 메모리를 관리하는지 살펴보장
프로세스의 주소공간은 각 프로세스에 제공되는 선형주소범위와 이 주소공간에서 프로세스가 사용할 수 있는 실제공간으로 나뉜다.
프로세스는 유효한 영역내에 있는 메모리 주소에만 접근할 수 있다. 더욱이 이러한 메모리읽기전용이나 실행불가 등으로 표시될있다. 만일 프로세스가 유요하지 않은 영역의 메모리 주소를 접근하려하거나 유효한 영역을 비정상적인 방법으로 접근할 경우, "segment fault"가 뜬다.
메모리영역은 다음과 같은 것들을 포함할 수 있다.
- 텍스트 섹션 : 실행파일의 코드에 대한 메모리맵
- 데이터 섹션 : 실행파일의 초기화된 전역변수에 대한 메모리맵
- bss 섹션 : 초기화되지 않은 전역변수를 포함하는 제로페이지(모두 0으로 초기화된 페이지)에 대한 메모리 맵
- 프로세스의 유저 공간 스택에 사용되는 제로페이지에 대한 메모리맵<- 유저공간의 스택임
- 프로세스 주소공간의 로드된 C라이브러리나 다이나믹 링커와 같은 공유 라이브러리를 위한 추가적인 텍스트/데이 터/bsstprtus
- 메모리 매핑된 파일들
- 공유 메모리 세그먼트
- malloc()에 생성된 익명의 메모리 매핑
메모리 서술자
- 커널은 프로세스의 주소공간을 메모리 서술자라는 자료구조로 표현한다. 이 구조체는 프로세스의 주소공간과 관련된 모든 정보를 포함하며
<linux/sched.h>에 정의돼있는 struct mm_struct으로 표현된다.
(2.6 이후에는 include/mm_types.h로 이동됨)
http://lxr.linux.no/linux+v3.1/include/linux/mm_types.h#L253
253struct mm_struct { 254 struct vm_area_struct * mmap; /* 메모리 영역 리스트 */ 255 struct rb_root mm_rb; /* 가상메모리 영역에 대한 레드블랙 트리 */ 256 struct vm_area_struct * mmap_cache; /* 최근에 사용된 메모리 영역 */ 257#ifdef CONFIG_MMU 258 unsigned long (*get_unmapped_area) (struct file *filp, 259 unsigned long addr, unsigned long len, 260 unsigned long pgoff, unsigned long flags); 261 void (*unmap_area) (struct mm_struct *mm, unsigned long addr); 262#endif 263 unsigned long mmap_base; /* base of mmap area */ 264 unsigned long task_size; /* size of task vm space */ 265 unsigned long cached_hole_size; /* if non-zero, the largest hole below free_area_cache */ 266 unsigned long free_area_cache; /* 첫번째 주소공간 hole */ 267 pgd_t * pgd; /* 페이지 글로벌 디렉터리 page global directory(pgd) */ 268 atomic_t mm_users; /* 해당주소공간을 사용하는 프로세스의 개수*/ 269 atomic_t mm_count; /* primary 참조 카운터 */ 270 int map_count; /* 가상메모리영역 개수 */ 271 272 spinlock_t page_table_lock; /* Protects page tables and some counters */ 273 struct rw_semaphore mmap_sem; 274 275 struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung 276 * together off init_mm.mmlist, and are protected 277 * by mmlist_lock 278 */ 279 280 281 unsigned long hiwater_rss; /* High-watermark of RSS usage */ 282 unsigned long hiwater_vm; /* High-water virtual memory usage */ 283 284 unsigned long total_vm, locked_vm, shared_vm, exec_vm; 285 unsigned long stack_vm, reserved_vm, def_flags, nr_ptes; 286 unsigned long start_code, end_code, start_data, end_data; 287 unsigned long start_brk, brk, start_stack; 288 unsigned long arg_start, arg_end, env_start, env_end; 289 290 unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */ 291 292 /* 293 * Special counters, in some configurations protected by the 294 * page_table_lock, in other configurations by being atomic. 295 */ 296 struct mm_rss_stat rss_stat; 297 298 struct linux_binfmt *binfmt; 299 300 cpumask_var_t cpu_vm_mask_var; 301 302 /* Architecture-specific MM context */ 303 mm_context_t context; 304 305 /* Swap token stuff */ 306 /* 307 * Last value of global fault stamp as seen by this process. 308 * In other words, this value gives an indication of how long 309 * it has been since this task got the token. 310 * Look at mm/thrash.c 311 */ 312 unsigned int faultstamp; 313 unsigned int token_priority; 314 unsigned int last_interval; 315 316 /* How many tasks sharing this mm are OOM_DISABLE */ 317 atomic_t oom_disable_count; 318 319 unsigned long flags; /* Must use atomic bitops to access the bits */ 320 321 struct core_state *core_state; /* coredumping support */ 322#ifdef CONFIG_AIO 323 spinlock_t ioctx_lock; 324 struct hlist_head ioctx_list; 325#endif 326#ifdef CONFIG_MM_OWNER 327 /* 328 * "owner" points to a task that is regarded as the canonical 329 * user/owner of this mm. All of the following must be true in 330 * order for it to be changed: 331 * 332 * current == mm->owner 333 * current->mm != mm 334 * new_owner->mm == mm 335 * new_owner->alloc_lock is held 336 */ 337 struct task_struct __rcu *owner; 338#endif 339 340 /* store ref to file /proc/<pid>/exe symlink points to */ 341 struct file *exe_file; 342 unsigned long num_exe_file_vmas; 343#ifdef CONFIG_MMU_NOTIFIER 344 struct mmu_notifier_mm *mmu_notifier_mm; 345#endif 346#ifdef CONFIG_TRANSPARENT_HUGEPAGE 347 pgtable_t pmd_huge_pte; /* protected by page_table_lock */ 348#endif 349#ifdef CONFIG_CPUMASK_OFFSTACK 350 struct cpumask cpumask_allocation; 351#endif352};
mm_users는 해당 주소공간을 사용하는 프로세스의 개수를 나타냄. 예를 들어 2개의 스레드가 주소공간을 공유한다며 mm_users는 2가 된다. mm_count 필드는 mm_struct에 대한 주 참조 카운터이다.All mm_users equate to one increment of mm_count.-> 무슨뜻이지? <참고 : http://www.iamroot.org/xe/?document_srl=42756>
또한 오직 mm_users가 0으로 될 때만(두 스레드가 종료되었을 때 ) mm_count가 감소한다. 결국 mm_count(mm_users아님???)가 0이되면 더 이상 mm_struct에 대한 참조가 없는 것이 되며, 이 구조체는 해제된다.
이 처럼, 두개의 카운터를 둠으로써 커널로 하여금 주 사용 카운터(mm_count)와 주소공간을 사용하는 프로세스의 개수(mm_users)를 구별하는 것이 간으토로 하고 있다.
mmap과 mm_rb 필드는 서로 다른 자료구조이지만, 해당 주소공간에 속하는 모든 메모리영역이라는 같은정보를 가지고 있다. mmap필드는 연결리스트로 저장하는 한편, 후자는 레드블랙트리로 저장한다. 레드블랙트리는 주어진 항목을 O(logN)시간안에 찾을 수 있다.
즉, 연결리스트로 자료구조를 mmap은 모든 원소에 대한 순회를 간단하고 효율적으로 처리할 수 있게 해주는 한편, 레드블랙트리로 구성된 mm_rb는 주어진 워ㅓㄴ소를 검색하기에 적합한다.
모든 mm_struct 구조체는 mmlist필드를 통하여 이중 연결리스트의 형태로 서로 연결돼있다. 이 리스트의 초기원소는 init_mm 메모리 서술자로, 이것은 init 프로세스의 주소공간을 표현한다. 또한 이 리스트는 kernel/fork.c에 정의돼있는 mmlist_lock을 사용하여 동시접근으로부터 자신을 보호한다. 메모리 서술자의 전체 개수는 같은 곳에 선언돼있는 전역 integer변수인 mmlist_nr에 저장돼있다.
[그림설명]
mmap과 mm_rb 필드는 서로 다른 자료구조이지만, 해당 주소공간에 속하는 모든 메모리영역이라는 같은정보를 가지고 있다. mmap필드는 연결리스트로 저장하는 한편, 후자는 레드블랙트리로 저장한다. 레드블랙트리는 주어진 항목을 O(logN)시간안에 찾을 수 있다.
즉, 연결리스트로 자료구조를 mmap은 모든 원소에 대한 순회를 간단하고 효율적으로 처리할 수 있게 해주는 한편, 레드블랙트리로 구성된 mm_rb는 주어진 워ㅓㄴ소를 검색하기에 적합한다.
모든 mm_struct 구조체는 mmlist필드를 통하여 이중 연결리스트의 형태로 서로 연결돼있다. 이 리스트의 초기원소는 init_mm 메모리 서술자로, 이것은 init 프로세스의 주소공간을 표현한다. 또한 이 리스트는 kernel/fork.c에 정의돼있는 mmlist_lock을 사용하여 동시접근으로부터 자신을 보호한다. 메모리 서술자의 전체 개수는 같은 곳에 선언돼있는 전역 integer변수인 mmlist_nr에 저장돼있다.
[그림설명]