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 


 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#endif 
352}; 
 
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에 저장돼있다.

[그림설명]