【进程地址空间】
1.内核除了管理本身的内存外,还必须管理进程的地址空间--也就是系统中每个用户空间进程所看到的内存。
进程只能访问有效范围内的内存地址,另外每个地址范围也具有特定的访问属性,如只读或不可执行等属性。
如果一个进程访问了不在有效范围中的地址,或以不正确的方式访问有效地址,那么内核就会终止该进程,并返回“段错误”信息。
内存区域可以包含各种内存对象,比如:代码段;数据段;BSS段(零页);堆;用户空间栈;C库、DLL等的代码段数据段bss段等;内存映射文件;共享内存等。
2. 内存描述符
内核使用内存描述符结构体(mm_struct)表示进程的地址空间,该结构包含了和进程地址空间有关的全部信息。
其中mm_users域记录正在使用该进程的进程数目。比如,如果两个进程共享该地址空间,那么mm_users的值便等于2;mm_count域是mm_struct结构体的主引用计数,只要mm_users不为0,那么mm_count值就等于1。当mm_users的值减为0(两个线程都退出)时,mm_count域的值才为0,此说明已经没有任何指向该mm_struct结构体的引用了,这时该结构体会被销毁。
所有的进程的mm_struct结构体都链接在双向链表中,该链表的首元素是init_mm内存描述符,代表init进程的地址空间。这个特性跟进程描述符很像,所有的进程描述符也是链接成了一个双向链表。
在进程的进程描述符中,mm域存放着该进程使用的内存描述符,所以current->mm便指向当前进程的内存描述符。
fork()函数利用copy_mm()函数复制父进程的内存描述符,也就是current->mm域给其子进程。
3. 内存区域
内存区域由vm_area_struct结构体描述(又称VMA),该结构体描述了指定地址空间内连续区间上的一个独立内存范围。
内核将每个内存区域作为一个单独的内存对象管理,每个内存区域都拥有一致的属性,比如访问权限等,另外,相应的操作也都一致。
采用面向对象的方法使VMA结构体可以代表多种类型的内存区域--比如内存映射文件或进程的用户空间栈等。
(个人理解:该结构体用于描述内存空间里某段内存的含义,比如从哪到哪为代码段,哪到哪为数据段,哪到哪位共享区,哪到哪为用户空间栈等,因此他们不能有内存重叠。且每一个进程地址空间都会有对应的内存区域来描述)
(mmap,内存映射,实际上就是一个内存区域vma的创建过程。通常用在文件映射,使对文件的访问变为内存操作,而不再是低效的文件I/O,也可以达到数据共享的作用)