1、甚么是mm_struct???
內(nèi)存描寫(xiě)符也用1個(gè)結(jié)構(gòu)體表示,這個(gè)結(jié)構(gòu)體的名字叫做mm_struct(內(nèi)存描寫(xiě)符),linux就是通過(guò)mm_struct這個(gè)結(jié)構(gòu)體來(lái)實(shí)現(xiàn)內(nèi)存管理。 1個(gè)進(jìn)程的虛擬地址空間主要由兩個(gè)數(shù)據(jù)結(jié)構(gòu)來(lái)描寫(xiě),1個(gè)是最高層次的mm_struct,1個(gè)是較高層次的vm_ares_struct。最高層次的mm_struct結(jié)構(gòu)描寫(xiě)了1個(gè)進(jìn)程的全部虛擬地址空間。較高層次的結(jié)構(gòu)vm_area_struct描寫(xiě)了虛擬地址空間的1個(gè)區(qū)間(簡(jiǎn)稱虛擬區(qū))。每一個(gè)進(jìn)程只有1個(gè)mm_struct結(jié)構(gòu),在每一個(gè)進(jìn)程的task_struct結(jié)構(gòu)體中,有1個(gè)指向該進(jìn)程的結(jié)構(gòu)。可以說(shuō),mm_struct結(jié)構(gòu)是對(duì)全部用戶空間的描寫(xiě)。
在進(jìn)程的task_struct結(jié)構(gòu)體中包括1個(gè)指向mm_struct結(jié)構(gòu)的指針,mm_struct用來(lái)描寫(xiě)1個(gè)進(jìn)程的虛擬地址空間。進(jìn)程的mm_struct則包括裝入的可履行映像信息和進(jìn)程的頁(yè)目錄指針pgd。該結(jié)構(gòu)還包括有指向vm_area_struct結(jié)構(gòu)的幾個(gè)指針,每一個(gè)vm_area_struct代表進(jìn)程的1個(gè)虛擬地址區(qū)間。vm_area_struct結(jié)構(gòu)含有指向vm_operations_struct結(jié)構(gòu)的1個(gè)指針,vm_operations_struct描寫(xiě)了在這個(gè)區(qū)間的操作。vm_operations_struct結(jié)構(gòu)中包括的是函數(shù)指針,其中open、close分別用于虛擬區(qū)間的打開(kāi)、關(guān)閉,而nopage用于當(dāng)虛擬頁(yè)面不再物理內(nèi)存而引發(fā)的”缺頁(yè)異常”時(shí)所調(diào)用的函數(shù),當(dāng)linux處理這1缺頁(yè)異常時(shí),就能夠?yàn)樾碌奶摂M內(nèi)存分配實(shí)際的物理內(nèi)存。
下面的linux管理內(nèi)存的大致結(jié)構(gòu):
2、mm_struct
每一個(gè)進(jìn)程都只有1個(gè)內(nèi)存描寫(xiě)符mm_struct。在每一個(gè)進(jìn)程的task_struct結(jié)構(gòu)中,有1個(gè)指向mm_struct的變量,這個(gè)變量常常是mm。
mm_struct是對(duì)進(jìn)程的地址空間(虛擬內(nèi)存)的描寫(xiě)。1個(gè)進(jìn)程的虛擬空間中可能有多個(gè)虛擬區(qū)間,對(duì)這些虛擬空間的組織方式有兩種,當(dāng)虛擬區(qū)較少時(shí)采取單鏈表,由mmap指針指向這個(gè)鏈表,當(dāng)虛擬區(qū)間多時(shí)采取紅黑樹(shù)進(jìn)行管理,由mm_rb指向這棵樹(shù)。由于程序中用到的地址常常具有局部性,因此,最近1次用到的虛擬區(qū)間極可能下1次還要用到,因此把最近用到的虛擬區(qū)間結(jié)構(gòu)放到高速緩存,這個(gè)虛擬區(qū)間就由mmap_cache指向。
指針pgt指向該進(jìn)程的頁(yè)目錄(每一個(gè)進(jìn)程都有自己的頁(yè)目錄),當(dāng)調(diào)度程序調(diào)度1個(gè)程序運(yùn)行時(shí),就將這個(gè)地址轉(zhuǎn)換成物理地址,并寫(xiě)入控制寄存器。
由于進(jìn)程的虛擬空間及下屬的虛擬區(qū)間有可能在不同的上下文中遭到訪問(wèn),而這些訪問(wèn)又必須互斥,所以在該結(jié)構(gòu)中設(shè)置了用于P,V操作的信號(hào)量mmap_sem。另外,page_table_lock也是為類似的目的而設(shè)置。
雖然每一個(gè)進(jìn)程只有1個(gè)虛擬空間,但是這個(gè)虛擬空間可以被別的進(jìn)程來(lái)同享。如:子進(jìn)程同享父進(jìn)程的地址空間,而mm_user和mm_count就對(duì)其計(jì)數(shù)。
另外,還描寫(xiě)了代碼段、數(shù)據(jù)段、堆棧段、參數(shù)段及環(huán)境段的起始和結(jié)束地址。
struct mm_struct
{
struct vm_area_struct *mmap; //指向虛擬區(qū)間(VMA)鏈表
struct rb_root mm_rb; //指向red_black樹(shù)
struct vm_area_struct *mmap_cache; //找到最近的虛擬區(qū)間
unsigned long(*get_unmapped_area)(struct file *filp,unsigned long addr,unsigned long len,unsigned long pgoof,unsigned long flags);
void (*unmap_area)(struct mm_struct *mm,unsigned long addr);
unsigned long mmap_base;
unsigned long task_size; //具有該結(jié)構(gòu)體的進(jìn)程的虛擬地址空間的大小
unsigned long cached_hole_size;
unsigned long free_area_cache;
pgd_t *pgd; //指向頁(yè)全局目錄
atomic_t mm_users; //用戶空間中有多少用戶
atomic_t mm_count; //對(duì)"struct mm_struct"有多少援用
int map_count; //虛擬區(qū)間的個(gè)數(shù)
struct rw_semaphore mmap_sem;
spinlock_t page_table_lock; //保護(hù)任務(wù)頁(yè)表和mm->rss
struct list_head mmlist; //所有活動(dòng)mm的鏈表
mm_counter_t _file_rss;
mm_counter_t _anon_rss;
unsigned long hiwter_rss;
unsigned long hiwater_vm;
unsigned long total_vm,locked_vm,shared_vm,exec_vm;
usingned long stack_vm,reserved_vm,def_flags,nr_ptes;
unsingned long start_code,end_code,start_data,end_data; //代碼段的開(kāi)始start_code ,結(jié)束end_code,數(shù)據(jù)段的開(kāi)始start_data,結(jié)束end_data
unsigned long start_brk,brk,start_stack; //start_brk和brk記錄有關(guān)堆的信息,start_brk是用戶虛擬地址空間初始化,brk是當(dāng)前堆的結(jié)束地址,start_stack是棧的起始地址
unsigned long arg_start,arg_end,env_start,env_end; //參數(shù)段的開(kāi)始arg_start,結(jié)束arg_end,環(huán)境段的開(kāi)始env_start,結(jié)束env_end
unsigned long saved_auxv[AT_VECTOR_SIZE];
struct linux_binfmt *binfmt;
cpumask_t cpu_vm_mask;
mm_counter_t context;
unsigned int faultstamp;
unsigned int token_priority;
unsigned int last_interval;
unsigned long flags;
struct core_state *core_state;
}
3、vm_area_struct
虛擬地址區(qū)間vm_area_struct是虛擬內(nèi)存的1部份,內(nèi)存描寫(xiě)符mm_struct指向全部虛擬空間,而vm_area_struct只是指向了虛擬空間的1段。較高層次的結(jié)構(gòu)vm_area_struct是由雙向鏈表鏈接起來(lái)的,它們是依照虛擬地址降序排序的,每一個(gè)這樣的結(jié)構(gòu)都對(duì)應(yīng)描寫(xiě)1個(gè)相鄰的地址空間范圍。之所以這樣分隔是由于每一個(gè)虛擬區(qū)間可能來(lái)源不同,有的可能來(lái)自可履行映像,有的可能來(lái)自同享庫(kù),而有的多是動(dòng)態(tài)內(nèi)存分配的內(nèi)存區(qū),所以對(duì)每一個(gè)由vm_area_struct結(jié)構(gòu)所描寫(xiě)的區(qū)間的處理操作和它前后范圍的處理操作不同,因此linux把虛擬內(nèi)存分割管理,并利用了虛擬內(nèi)存處理例程vm_ops來(lái)抽象對(duì)不同來(lái)源虛擬內(nèi)存的處理方法。不同的虛擬區(qū)間其處理操作可能不同,linux在這里利用了面向?qū)ο蟮乃枷耄窗?個(gè)虛擬區(qū)間看成是1個(gè)對(duì)象,用vm_area_struct描寫(xiě)這個(gè)對(duì)象的屬性,其中的vm_operation結(jié)構(gòu)描寫(xiě)了在這個(gè)對(duì)象上的操作。
struct vm_area_struct
{
struct mm_struct *vm_mm; //虛擬地址區(qū)間所在的地址空間
unsigned long vm_start; //在vm_mm中的起始地址
unsigned long vm_end; //在vm_mm中的結(jié)束地址
struct vm_area_struct *vm_next; //指向下1個(gè)虛擬區(qū)間
pgprot_t vm_page_prot; //虛擬區(qū)間的存取極限
unsigned long vm_flags; //描寫(xiě)對(duì)虛擬區(qū)間進(jìn)行操作的標(biāo)志
struct rb_node vm_rb;
union
{
struct
{
struct list_head list;
void *parent;
struct vm_area_struct *head;
} vm_set;
struct raw_prio_tree_node prio_tree_node;
} shared;
struct list_head anon_vma_node;
struct anon_vma *anon_vma;
const struct vm_operations_struct *vm_ops; //對(duì)這個(gè)區(qū)間進(jìn)行操作的函數(shù)
unsigned long vm_pgoff;
struct file* vm_file;
void *vm_private_data;
unsigned long vm_truncate_count;
}
4、vm_operations_struct
vm_operations_struct結(jié)構(gòu)中包好的是函數(shù)指針,其中open、close分別用于虛擬內(nèi)存的打開(kāi)、關(guān)閉,而nopage用于當(dāng)虛擬內(nèi)存頁(yè)面沒(méi)有實(shí)際的物理內(nèi)存映照而引發(fā)的”缺頁(yè)異常”時(shí)所調(diào)用的函數(shù)指針。
struct vm_operations_struct
{
void (*open)(struct vm_area_strucr *area);
void (*close)(struct vm_area_struct *area);
struct page *(nopage)(struct vm_area_struct *area,unsigned long address,int unused);
}
5、linux虛擬內(nèi)存管理數(shù)據(jù)結(jié)構(gòu)圖(本來(lái)想自己畫(huà)的,結(jié)果發(fā)現(xiàn)這個(gè)圖真的不錯(cuò),所以直接粘過(guò)來(lái)):