線性地址-->物理地址。也是從分段單元到分頁(yè)單元的轉(zhuǎn)換。在linux中,用戶程序所使用的地址與硬件使用的物理地址是不等同的。虛擬內(nèi)存引入一個(gè)間接層,它使得許多操作成為可能。在引入虛擬內(nèi)存這個(gè)概念和方法后,在系統(tǒng)中運(yùn)行的程序可以分配比物理內(nèi)存更多的內(nèi)存。而linux的地址有分下面幾個(gè)類(lèi)型:用戶虛擬地址:用戶空間所能看到的常規(guī)地址物理地址:在處理器和系統(tǒng)內(nèi)存之間使用總線地址:在外圍總線和內(nèi)存之間" />

日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

:Linux 內(nèi)存管理 重要結(jié)構(gòu)體

系統(tǒng) 2205 0
虛擬內(nèi)存地址與實(shí)際內(nèi)存地址之間的關(guān)系,是如此轉(zhuǎn)換的,邏輯地址-->線性地址-->物理地址。也是從分段單元到分頁(yè)單元的轉(zhuǎn)換。在 linux中,用戶程序所使用的地址與硬件使用的物理地址是不等同的。虛擬內(nèi)存引入一個(gè)間接層,它使得許多操作成為可能。在引入虛擬內(nèi)存這個(gè)概念和方法 后,在系統(tǒng)中運(yùn)行的程序可以分配比物理內(nèi)存更多的內(nèi)存。而linux的地址有分下面幾個(gè)類(lèi)型:

用戶虛擬地址:用戶空間所能看到的常規(guī)地址
物 理地址:在處理器和系統(tǒng)內(nèi)存之間使用
總線地址:在外圍總線和內(nèi)存之間使用
內(nèi)核邏輯地址:組成內(nèi)核的常規(guī)地址空間,該地址映射了部分或者全 部?jī)?nèi)存,并經(jīng)常被視為物理地址。
內(nèi)核虛擬地址:其與物理地址的映射不必是線性的和一對(duì)一的,所有的邏輯地址都是內(nèi)核虛擬地址,但是有些內(nèi)核地址不 是邏輯地址。

UMA,一致內(nèi)存訪問(wèn)體系結(jié)構(gòu),此結(jié)構(gòu)通常用pg_data_t來(lái)引用,系統(tǒng)中每個(gè)節(jié)點(diǎn)鏈接到一個(gè)以NULL結(jié)尾的 pgdat_list鏈表中,而其中的每個(gè)節(jié)點(diǎn)利用pg_data_tnode_next字段鏈接到下一個(gè)節(jié)點(diǎn)。

對(duì)大型機(jī)來(lái)說(shuō),內(nèi)存會(huì)分 成很多簇,每個(gè)簇都被認(rèn)為是一個(gè)節(jié)點(diǎn)。struct pg_data_t體現(xiàn)此概念,系統(tǒng)中的每個(gè)節(jié)點(diǎn)鏈接到一個(gè)以NULL結(jié)尾的pgdat_list臉表中,而其中的每個(gè)節(jié)點(diǎn)利用 pg_data_tnode_next連接到下一個(gè)節(jié)點(diǎn)。內(nèi)存中,每個(gè)節(jié)點(diǎn)被分成很多的成為管理區(qū)的塊,而用于表示內(nèi)存中的某個(gè)范圍,一個(gè)管理區(qū)由 sruct zone_struct描述,并被定義為zone_t,且每個(gè)管理區(qū)的類(lèi)型都是ZONE_DMA(低端范圍的物理內(nèi)存,內(nèi)存首部 16MB),ZONE_NORMAL(由內(nèi)核直接映射到線性地址空間的較高部分,16MB--896MB)或者ZONE_HIGHMEM(系統(tǒng)中預(yù)留的可 用內(nèi)存空間,不被內(nèi)核直接映射,896MB--末尾)中的一種。而三者中,ZONE_NORMAL是影響系統(tǒng)性能最重要的管理區(qū)。

系統(tǒng)的 內(nèi)存劃分成大小確定的許多塊,這些塊用struct page結(jié)構(gòu)體來(lái)描述,所有的結(jié)構(gòu)都存儲(chǔ)在一個(gè)全局mem_map數(shù)組中,通常存放在ZONE_NORMAL的首部,或者就在小內(nèi)存系統(tǒng)中裝入內(nèi)核映像而 預(yù)留的區(qū)域之后。就因?yàn)閆ONE_NORMAL大小有限,所以linux才會(huì)提出高端內(nèi)存這個(gè)概念。
linux中,運(yùn)用page結(jié)構(gòu)體來(lái)保存內(nèi)核 需要知道的所有物理內(nèi)存信息,對(duì)系統(tǒng)中每個(gè)物理頁(yè),都有一個(gè)page結(jié)構(gòu)體相對(duì)應(yīng)。

內(nèi)存中的每個(gè)節(jié)點(diǎn)都由pa_data_t描述,而此則 由struct pglist_data定義而來(lái),在分配一個(gè)頁(yè)面時(shí),linux 采用節(jié)點(diǎn)局部分配的策略,從最靠近運(yùn)行中的cpu的節(jié)點(diǎn)分配內(nèi)存,由于進(jìn)程往往是在同一個(gè)cpu上運(yùn)行,因此從當(dāng)前節(jié)點(diǎn)得到的內(nèi)存很有可能被用到,每個(gè)管 理區(qū)由一個(gè)struct zone_t描述,此結(jié)構(gòu)體用于跟蹤頁(yè)面使用情況統(tǒng)計(jì)數(shù),空閑區(qū)域信息和鎖信息等,在<linux/mmzone.h>文件中聲明.

以 下這三個(gè)結(jié)構(gòu)體互相結(jié)合,彼此指向形成了一個(gè)關(guān)于內(nèi)存分配的樹(shù)型結(jié)構(gòu)。

typedef struct pglist_data {
??????? zone_t node_zones[MAX_NR_ZONES];該節(jié)點(diǎn)所在管理區(qū)為HIGHMEM、NORMAL、DAM三者之一。
??????? zonelist_t node_zonelists[NR_GFPINDEX];按照分配時(shí)的管理區(qū)順序排列。通過(guò)page_alloc.c中的 bulid)zaonelists()建立順序。
??????? struct page *node_mem_map;struct page數(shù)組中的第一個(gè)頁(yè)面被放置在全局mem_map數(shù)組中。
??????? unsigned long *valid_addr_bitmap;描述內(nèi)存節(jié)點(diǎn)中空洞的位圖,因?yàn)椴](méi)有實(shí)際的內(nèi)存空間存在。
??????? struct bootmem_data *bdata;指向內(nèi)存引導(dǎo)程序
??????? unsigned long node_start_paddr;節(jié)點(diǎn)的起始物理地址
??????? unsigned long node_start_mapnr;
它 指出該節(jié)點(diǎn)在全局mem_map中的頁(yè)面偏移,通過(guò)計(jì)算mem_map與該節(jié)點(diǎn)的局部mem_map中成為lmem_map之間的頁(yè)面數(shù),得到頁(yè)面偏移。
??????? unsigned long node_size;管理區(qū)中的頁(yè)面總數(shù)
??????? int node_id;節(jié)點(diǎn)的ID號(hào)(NID),從0開(kāi)始
??????? struct pglist_data *node_next;指向下一個(gè)節(jié)點(diǎn)。
} pg_data_t;

所有的節(jié)點(diǎn)都有一個(gè)pgdat_list的鏈表維護(hù),這些節(jié)點(diǎn) 都放在該鏈表中。

typedef struct zone_struct {
??????? spinlock_t??????????????? lock;并行訪問(wèn)時(shí)保護(hù)該管理區(qū)的自旋鎖。
??????? unsigned long??????????????? offset;
??????? unsigned long??????????????? free_pages;該管理區(qū)中空閑頁(yè)面的總數(shù)。
??????? unsigned long??????????????? inactive_clean_pages;
??????? unsigned long??????????????? inactive_dirty_pages;
??????? unsigned long??????????????? pages_min, pages_low, pages_high;管理區(qū)極值
??????? struct list_head??????? inactive_clean_list;
??????? free_area_t??????????????? free_area[MAX_ORDER];空閑區(qū)域位圖。
??????? char??????????????????????? *name;管理區(qū)的字符串名字“DMA”“Normal”“HighMem”
??????? unsigned long??????????????? size;該管理區(qū)的大小,以頁(yè)面數(shù)計(jì)算
??????? struct pglist_data??????? *zone_pgdat;指向父pg_data_t
??????? unsigned long??????????????? zone_start_paddr;節(jié)點(diǎn)的起始物理地址
??????? unsigned long??????????????? zone_start_mapnr;節(jié)點(diǎn)在全局mem_map中的頁(yè)面偏移
??????? struct page??????????????? *zone_mem_map;設(shè)計(jì)的管理區(qū)在全局mem_map中的第一頁(yè)
} zone_t;

unsigned long??????????????? pages_min, pages_low, pages_high;管理區(qū)極值
當(dāng)空閑頁(yè)面數(shù)達(dá)到pages_low時(shí),伙伴分配器就會(huì)喚醒kswapd(守護(hù)程序)釋放頁(yè)面,默認(rèn)值是 pages_low的兩倍。
當(dāng)達(dá)到pages_min時(shí),分配器會(huì)以同步方式啟動(dòng)kswapd。
kswapd被喚醒并開(kāi)始釋放頁(yè)面后,在 high個(gè)頁(yè)面被釋放以前,是不會(huì)認(rèn)為該管理區(qū)已經(jīng)“平衡”的,當(dāng)?shù)竭_(dá)極值后,kswapd再次睡眠。

struct page {
?? ?unsigned long flags;//page狀態(tài)的標(biāo)志信息。
?? ?atomic_t _count;//count: page的訪問(wèn)計(jì)數(shù),為0說(shuō)明page空閑,大于0時(shí),page被一個(gè)或多個(gè)進(jìn)程真正使用或者kernel用于在等待I/O。?? ?
?? ?union {
?? ??? ?atomic_t _mapcount;
?? ??? ?struct {?? ??? ?/* SLUB */
?? ??? ??? ?u16 inuse;
?? ??? ??? ?u16 objects;
?? ??? ?};
?? ?};
?? ?union {
?? ???? struct {
?? ??? ?unsigned long private;
//private:這個(gè)保存了一些和mapping(文件mapping到內(nèi)存)有關(guān)的一些特定的信息。
// 如果page是一個(gè)buffer page,則它就保存了一個(gè)指向buffer_head的指針。
?? ??? ?struct address_space *mapping;
//當(dāng)文件或設(shè)備需要內(nèi)存映射,文件或設(shè)備的inode對(duì)象有一個(gè)address_space類(lèi) 型的成員。如果page屬于這個(gè)文件或設(shè)備,mapping將指向inode中這個(gè)成員。如果page不屬于任何文件或設(shè)備,但是mapping被設(shè)置 了,則mapping指向了一個(gè)address_space類(lèi)型的swapper_space對(duì)象,則page用于管理交換地址空間 (swap address space)了。
?? ???? };
#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
?? ???? spinlock_t ptl;
#endif
?? ???? struct kmem_cache *slab;?? ?/* SLUB: Pointer to slab */
?? ???? struct page *first_page;?? ?/* Compound tail pages */
?? ?};
?? ?union {
?? ??? ?pgoff_t index;
//index:這個(gè)成員根據(jù)page的使用的目的有2種可能的含義。
// 第一種情況:如果page是file mapping的一部分,它指明在文件中的偏移。如果page是交換緩存,則它指明在address_space所聲明的對(duì)象: swapper_space(交換地址空間)中的偏移。
//第二種情況:如果這個(gè)page是一個(gè)特殊的進(jìn)程將要釋放的一個(gè)page塊,則這是一個(gè) 將要釋放的page塊的序列值,這個(gè)值在__free_page_ok()函數(shù)中設(shè)置。
?? ??? ?void *freelist;?? ??? ?/* SLUB: freelist req. slab lock */
?? ?};
?? ?struct list_head lru;//lru: page交換調(diào)度策略使用。page可能被調(diào)度到active_list或者inactive_list隊(duì)列里。就是使用lru這個(gè)list_head。
#if defined(WANT_PAGE_VIRTUAL)
?? ?void *virtual;//不再用于將high memory的映射到ZONE_NORMAL區(qū)域的作用了,除了一些其他的體系結(jié)構(gòu)會(huì)用到外。
#endif /* WANT_PAGE_VIRTUAL */
#ifdef CONFIG_CGROUP_MEM_RES_CTLR
?? ?unsigned long page_cgroup;
#endif
};

linux采用了一種與具體體系結(jié)構(gòu)無(wú)關(guān)代碼 的三層頁(yè)表機(jī)制來(lái)完成內(nèi)存管理,即使底層的體系結(jié)構(gòu)并不支持這個(gè)概念。每一個(gè)進(jìn)程都有一個(gè)指向其自己的PGD指針 (mm_struct->pgd),這就是一個(gè)物理頁(yè)面號(hào),其中包含了一個(gè)pgd_t類(lèi)型的數(shù)組,進(jìn)程頁(yè)表的載入是通過(guò)把這個(gè)結(jié)構(gòu)體復(fù)制到cr3寄 存器完成。PGD表中每個(gè)有效的項(xiàng)都指向一個(gè)頁(yè)面號(hào),此頁(yè)面號(hào)包含一個(gè)pmd_t類(lèi)型的PMD項(xiàng)數(shù)組,每一個(gè)pmd_t又指向另外的頁(yè)面號(hào),這些頁(yè)面號(hào)由 很多個(gè)pte_t類(lèi)型的PTE構(gòu)成,而pte_t最終指向包含真正用戶數(shù)組的頁(yè)面。

整體結(jié)構(gòu)是這樣的:PGD進(jìn)程內(nèi)偏移量PMD頁(yè)面號(hào)內(nèi) 偏移量PTE頁(yè)面號(hào)內(nèi)偏移量數(shù)據(jù)號(hào)內(nèi)偏移量。這些結(jié)構(gòu)各自擁有自己的偏移量(offset)在尋址過(guò)程中,不斷的通過(guò)基地址和偏移量來(lái)找到下一個(gè)相關(guān)結(jié)構(gòu) 體最后尋到帶有用戶數(shù)據(jù)的頁(yè)面號(hào)。

由于所有在vmlinuz中的普通內(nèi)核代碼都編譯成以PAGE_OFFSET+1MB為起始地址,實(shí)際 上系統(tǒng)將內(nèi)核裝載到以第一個(gè)1MB(0x00100000)為起始地址,實(shí)際上系統(tǒng)內(nèi)核裝載到以第一個(gè)1MB為起始地址的物理空間中,第一個(gè)1MB的地址 常在以些設(shè)備用作和BISO進(jìn)行通訊的地方自行跳過(guò)。該文件中的引導(dǎo)初始化代碼總是把虛擬地址減去__PAGE_OFFSET,從而獲得以1M為起始地址 的物理地址。在開(kāi)啟換頁(yè)單元以前,必須首先建立相應(yīng)的頁(yè)表映射,從而將8MB的物理空間轉(zhuǎn)換為虛擬地址PAGE_OFFSET.

而物理空 間和struct page之間的映射概念也很重要,系統(tǒng)將內(nèi)核映像裝載到1MB物理地址起始位置,這個(gè)物理地址就是虛擬地址 PAGE_OFFSET+0x00100000.物理內(nèi)存為內(nèi)核映像預(yù)留了8MB的虛擬空間,耗個(gè)空間可以被兩個(gè)PGD所訪問(wèn)到,linux為 ZONE_DMA預(yù)留了16MB的內(nèi)存空間,所以真正被內(nèi)核分配使用的內(nèi)存起始位置應(yīng)在0xc1000000,這個(gè)位置久違全局量mem_map所在的位 置。通過(guò)把物理地址作為mem_map里的一個(gè)下標(biāo),從而將其轉(zhuǎn)換成對(duì)應(yīng)的struct page。通過(guò)把物理地址位右移PAGE_SHIFT位,從而將右移后的物理地址作為物理地址0開(kāi)始的頁(yè)面號(hào)PFN,同樣也是mem_map數(shù)組的一個(gè)下 標(biāo)。??
在linux中,為了可以更快的運(yùn)行程序,從內(nèi)存中裝入數(shù)據(jù),還設(shè)置了高速緩存管理。其實(shí)在,基本上都存在一級(jí)緩存和二級(jí)緩存,后者更大一點(diǎn),但是速度要 慢的一些。而地址映射高級(jí)緩存行的方式因?yàn)轶w系結(jié)構(gòu)的不同可能會(huì)有差別,但是基本會(huì)是如下三個(gè)方法:
1直接映射,每個(gè)內(nèi)存塊只與唯一一個(gè)可能的高 速緩存相映射
2關(guān)聯(lián)映射,任意的內(nèi)存塊可以與任意的高速緩存行相對(duì)應(yīng)
3關(guān)聯(lián)集映射,任意的內(nèi)存塊可以與任意的高速緩存行相映射,但是只能 在一個(gè)可用行的子集里面映射

虛擬內(nèi)存的好處之一就是可以讓進(jìn)程都有屬于自己的虛擬地址空間,這種虛擬地址空間可以通過(guò)操作系統(tǒng)映射到物理 內(nèi)存。對(duì)于進(jìn)程,它通過(guò)一個(gè)頁(yè)表項(xiàng)指針指向一個(gè)只讀的全局全零頁(yè)面,以實(shí)現(xiàn)在進(jìn)程的線性地址空間中保留空間。一旦進(jìn)程對(duì)該頁(yè)面進(jìn)行寫(xiě)操作,就會(huì)發(fā)生缺頁(yè)中 斷,這時(shí)系統(tǒng)會(huì)分配一個(gè)新的全零頁(yè)面,并由一個(gè)頁(yè)表指定,且標(biāo)記為可寫(xiě),新的全零頁(yè)面看起來(lái)和原來(lái)的全局全零頁(yè)面完全一樣。

地址空間由 sruct mm_struct結(jié)構(gòu)體來(lái)管理,而它到struct page之間,還需要有幾個(gè)步驟,它們之間的關(guān)系是通過(guò)如下結(jié)構(gòu)體相連,并且這些結(jié)構(gòu)體構(gòu)成了一個(gè)關(guān)于文件的各個(gè)方面的描述:

struct mm_struct,struct vm_area_struct,struct _file,struct vm_operations_struct,struct dentry,struct inode,struct address_space,struct address_space_operations,struct page.

描述進(jìn)程地址 空間,一個(gè)進(jìn)程只有一個(gè)mm_struct結(jié)構(gòu),且該結(jié)構(gòu)在進(jìn)程用戶空間中由多個(gè)線程共享,線程正是通過(guò)任務(wù)鏈表里的任務(wù)是否指向同一個(gè) mm_struct來(lái)判定的。主要字段:
struct mm_struct{
??? struct vm_area_struct * mmap;地址空間中所有VMA的鏈表首部
??? struct vm_area_struct * mmap_avl;
??? rb_root_t mm_rb;
??? struct vm_area_struct * mmap_cache;最后一次通過(guò)find_vma()找到的VMA存放處
??? pgd_t * pgd;全局目錄表的起始地址
??? atomic_t mm_users;訪問(wèn)用戶空間部分的用戶計(jì)數(shù)值
??? atomic_t mm_count;匿名用戶計(jì)數(shù)值
??? int map_count;正在被使用中的vma數(shù)量
??? struct semaphore mmap_sem;讀寫(xiě)保護(hù)鎖,長(zhǎng)期有效
??? spinlock_t page_table_lock;用于保護(hù)mm_struct中大部分字段
??? struct list_head mmlist;所有的mm_struct結(jié)構(gòu)通過(guò)它鏈接在一起
??? unsigned long start_code, end_code, start_data, end_data代碼段和數(shù)據(jù)段的起始地址和中止地址。
??? unsigned long start_brk, brk, start_stack;堆的起始地址和結(jié)束地址,棧的起始地址和結(jié)束地址
??? unsigned long arg_start, arg_end, env_start, env_end;命令行參數(shù)的起始地址和結(jié)束地址,環(huán)境變量區(qū)域的起始地址和結(jié)束地址。
??? unsigned long rss, total_vm,locked_vm; (resident set -->rss 某一時(shí)刻,一般一個(gè)進(jìn)程虛存空間不會(huì)完全在內(nèi)存中,一般駐留在內(nèi)存中的為其虛存空間的子集,rss描述有多少頁(yè)駐留內(nèi)存中)
駐留集的大小是該進(jìn)程常駐內(nèi)存的頁(yè)面數(shù),不包括全局零頁(yè)面,進(jìn)程 中所有vma區(qū)域的內(nèi)存空間總和,內(nèi)存中被鎖住的常駐頁(yè)面數(shù)。
??? unsigned long def_flags;VM_LOCKED用于指定在默認(rèn)情況下將來(lái)所有的映射是上鎖還是未鎖。
??? unsigned long cpu_vm_mask;
??? unsigned long swap_cnt;
??? unsigned long swap_address;當(dāng)換出整個(gè)進(jìn)程時(shí),頁(yè)換出進(jìn)程記錄最后一次被換出的地址
??? mm_context_t context;
}

與 內(nèi)存區(qū)域描述器相關(guān)的函 數(shù):mm_init(),allocate_mm(),mm_alloc(),exit_mmap(),copy_mm(),free_mm().

系 統(tǒng)中第一個(gè)mm_struct通過(guò)init_mm()初始化,以后的mm_struct都會(huì)通過(guò)復(fù)制它來(lái)進(jìn)行設(shè)置,所以第一個(gè)要手動(dòng)靜態(tài)設(shè)置,這是一個(gè)模 板:
mm_rb:RB_ROOT,
pgd:swapper_pg_dir,
mm_users:ATOMIC_INIT(2),
mm_count:ATOMIC_INIT(1),
mmap_sem:__RWSEM_INITIALLZER(name,mmap_sem),
page_table_lock:SPIN_LOCK_UNLOCKED,
mmlist:LIST_HEAD_INIT(name.mmlist),

而 系統(tǒng)用于分配mm_struct結(jié)構(gòu)的函數(shù)有兩個(gè):Allocate_mm()是一個(gè)預(yù)處理宏,從slab allocator中分配mm,而mm_alloc()從slab中分配,然后init.

源代碼主要語(yǔ)句:

static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
函數(shù)為 給定的進(jìn)程復(fù)制一份mm,僅在創(chuàng)建一個(gè)新進(jìn)程后且需要它自己的mm時(shí)由do_fork調(diào)用。
{
??? struct mm_struct * mm, *oldmm;
??? int retval;
??? tsk->min_flt = tsk->maj_flt = 0;初始化與內(nèi)存管理相關(guān)的task_struct字段,tsk是一個(gè)進(jìn)程控制塊。
??? tsk->nvcsw = tsk->nivcsw = 0;
??? tsk->mm = NULL;
??? tsk->active_mm = NULL;
??? oldmm = current->mm;借用當(dāng)前運(yùn)行進(jìn)程的mm來(lái)復(fù)制。
??? if (clone_flags & CLONE_VM) {如果設(shè)置clone_vm,則子進(jìn)程將與父進(jìn)程共享mm
??? ??? atomic_inc(&oldmm->mm_users);用戶數(shù)量加1,以便于不會(huì)過(guò)早銷(xiāo)毀
??? ??? mm = oldmm;
??? ??? goto good_mm;
??? }
??? mm = dup_mm(tsk);//鏈接過(guò)程,以及文件信息的設(shè)置。
good_mm:
??? mm->token_priority = 0;
??? mm->last_interval = 0;
??? tsk->mm = mm;
??? tsk->active_mm = mm;
??? return 0;
}

static struct mm_struct * mm_init(struct mm_struct * mm, struct task_struct *p)
{
??? atomic_set(&mm->mm_users, 1);用戶數(shù)為1
??? atomic_set(&mm->mm_count, 1);mm引用數(shù)為1
??? init_rwsem(&mm->mmap_sem);初始化保護(hù)vma鏈表的信號(hào)量
??? INIT_LIST_HEAD(&mm->mmlist);初始化mm鏈表
??? mm->flags = (current->mm) ? current->mm->flags : MMF_DUMP_FILTER_DEFAULT;設(shè)置標(biāo)識(shí)位
??? mm->core_waiters = 0;
??? mm->nr_ptes = 0;
??? set_mm_counter(mm, file_rss, 0);
??? set_mm_counter(mm, anon_rss, 0);
??? spin_lock_init(&mm->page_table_lock);
??? rwlock_init(&mm->ioctx_list_lock);
??? mm->ioctx_list = NULL;
??? mm->free_area_cache = TASK_UNMAPPED_BASE;
??? mm->cached_hole_size = ~0UL;
??? mm_init_owner(mm, p);//void mm_init_owner(struct mm_struct *mm, struct task_struct *p){mm->owner = p;}
??? if (likely(!mm_alloc_pgd(mm))) {
??? ??? mm->def_flags = 0;
??? ??? return mm;
??? }
??? free_mm(mm);
??? return NULL;

#define allocate_mm()??? (kmem_cache_alloc(mm_cachep, GFP_KERNEL))
#define free_mm(mm)??? (kmem_cache_free(mm_cachep, (mm)))

struct mm_struct * mm_alloc(void)
{
??? struct mm_struct * mm;
??? mm = allocate_mm();//kmem_cache_alloc(mm_cachep, GFP_KERNEL)從slab分配器分配一個(gè)mm_struct
??? if (mm) {
??? ??? memset(mm, 0, sizeof(*mm));字段歸零
??? ??? mm = mm_init(mm, current);//初始化
??? }
??? return mm;
}

進(jìn)程的地址空間很少用滿,而一般僅僅用到其中一些分離的區(qū)域,這個(gè)區(qū)域由結(jié)構(gòu)體 vm_area_struct來(lái)表示,區(qū)域之間是不會(huì)交叉的,各自代表一個(gè)有著相同屬性和用途的地址集合。一個(gè)進(jìn)程所有被映射的區(qū)域都可以在/proc /PID/maps里面看到。

當(dāng)一個(gè)文件被映射到內(nèi)存,則可以通過(guò)vm_file字段得到struct_file.而這個(gè)字段又指向 struct inode,索引節(jié)點(diǎn)用于找到struct address_space,而在后者中,包含與文件有關(guān)的所有信息,包括一系列指向與文件系統(tǒng)相關(guān)操作函數(shù)的指針。

struct vm_area_struct {
??? struct mm_struct * vm_mm;所述的mm_struct
??? unsigned long? vm_start;這個(gè)區(qū)域的起始地址
??? unsigned long vm_end;這個(gè)區(qū)域的結(jié)束地址
??? struct vm_area_struct * vm_next;一個(gè)地址空間中的所有vma都按地址空間次序通過(guò)該字段簡(jiǎn)單的鏈接在一起。
??? pgrot t_vm_page_prot;對(duì)應(yīng)的每個(gè)pte里的保護(hù)標(biāo)志位
??? unsigned long vm_flags;這個(gè)vma的保護(hù)標(biāo)志位和屬性標(biāo)志位
??? short vm_avl_height;
??? rb_node_ vm_rb;所有的vma都存儲(chǔ)在一個(gè)紅黑樹(shù)上以加快查找速度
??? struct vm_area_struct * vm_avl_left;
??? struct vm_area_struct * vm_avl_rigth;??
??? struct vm_area_struct * vm_next_share;把文件映射而來(lái)的vma共享區(qū)域鏈接在一起
??? struct vm_area_struct ** vm_pprev_share;vm_next_share的輔助指針
??? struct vm_operations_struct * vm_ops;包含指向與磁盤(pán)同步操作時(shí)所需要函數(shù)的指針。此字段包含有指向open(),close(),nopage()的函數(shù)指針
??? unsigned long vm_pgoff;在已被映射文件里對(duì)齊頁(yè)面的偏移
??? struct file * vm_file;指向被映射的文件的指針
??? unsigned long vm_raend;預(yù)讀窗口的結(jié)束地址,在發(fā)生錯(cuò)誤時(shí),一些額外的頁(yè)面將被收回,這個(gè)值決定了這些額外頁(yè)面的個(gè)數(shù)。
??? void * vm_private_data;一些設(shè)備驅(qū)動(dòng)私有數(shù)據(jù)的存儲(chǔ),與內(nèi)存管理無(wú)關(guān)。
}

pgrot t_vm_page_prot;對(duì)應(yīng)的每個(gè)pte里的保護(hù)標(biāo)志位:
_PAGE_PRESENT頁(yè)面常駐內(nèi)存,不進(jìn)行換出操作
_PAGE_PROTNONE 頁(yè)面常駐內(nèi)存,但不可訪問(wèn)
_PAGE_RW頁(yè)面可能被寫(xiě)入時(shí)設(shè)置該位
_PAGE_USER頁(yè)面可以被用戶空間訪問(wèn)時(shí)設(shè)置該位
_PAGE_DIRTY 頁(yè)面被寫(xiě)入時(shí)設(shè)置該位
_PAGE_ACCESSED頁(yè)面被訪問(wèn)時(shí)設(shè)置該位

unsigned long vm_flags;這個(gè)vma的保護(hù)標(biāo)志位和屬性標(biāo)志位

保護(hù)標(biāo)志位
VM_READ頁(yè)面可能被讀取
VM_WRITE頁(yè)面可 能被寫(xiě)入
VM_EXEC頁(yè)面可能被執(zhí)行
VM_SHARED頁(yè)面可能被共享
VM_DONTCOPY vma不能在fork時(shí)被復(fù)制
VM_DONTEXPAND 防止一個(gè)區(qū)域被重新設(shè)置大小。標(biāo)志位沒(méi)有被使用過(guò)

struct vm_operations_struct {
??? void (*open) (struct vm_area_struct * area);
??? void (*close) (struct vm_area_struct * area);
??? struct page * (*nopage)(struct vm_area_struct *area, unsigned long address, int write_access);
}?

struct address_space {定義的文件信息
??? struct inode??? ??? *host;
??? struct radix_tree_root??? page_tree;
??? rwlock_t??? ??? tree_lock;
??? unsigned int??? ??? i_mmap_writable;
??? struct prio_tree_root??? i_mmap;
??? struct list_head??? i_mmap_nonlinear;
??? spinlock_t??? ??? i_mmap_lock;
??? unsigned int??? ??? truncate_count;
??? unsigned long??? ??? nrpages;在地址空間中正被使用且常駐內(nèi)存的頁(yè)面數(shù)
??? pgoff_t??? ??? ??? writeback_index;
??? const struct address_space_operations *a_ops;操縱文件系統(tǒng)的函數(shù)結(jié)構(gòu)。每一個(gè)文件系統(tǒng)都提供其自身的operations.
??? unsigned long??? ??? flags;
??? struct backing_dev_info *backing_dev_info;
??? spinlock_t??? ??? private_lock;
??? struct list_head??? private_list;
??? struct address_space??? *assoc_mapping;????
}?

struct address_space_operations {定義的函數(shù)方法
??? int (*writepage)(struct page *page, struct writeback_control *wbc);
??? int (*readpage)(struct file *, struct page *);
??? void (*sync_page)(struct page *);
??? int (*writepages)(struct address_space *, struct writeback_control *);
??? int (*set_page_dirty)(struct page *page);
??? int (*readpages)(struct file *filp, struct address_space *mapping,struct list_head *pages, unsigned nr_pages);
??? int (*prepare_write)(struct file *, struct page *, unsigned, unsigned);
??? int (*commit_write)(struct file *, struct page *, unsigned, unsigned);
??? int (*write_begin)(struct file *, struct address_space *mapping,loff_t pos, unsigned len, unsigned flags,struct page **pagep, void **fsdata);
??? int (*write_end)(struct file *, struct address_space *mapping,loff_t pos, unsigned len, unsigned copied,struct page *page, void *fsdata);
??? sector_t (*bmap)(struct address_space *, sector_t);
??? void (*invalidatepage) (struct page *, unsigned long);
??? int (*releasepage) (struct page *, gfp_t);
??? ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,loff_t offset, unsigned long nr_segs);
??? int (*get_xip_mem)(struct address_space *, pgoff_t, int,void **, unsigned long *);
??? int (*migratepage) (struct address_space *,struct page *, struct page *);
??? int (*launder_page) (struct page *);
};

:Linux 內(nèi)存管理 重要結(jié)構(gòu)體


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 方城县| 大厂| 怀仁县| 泌阳县| 和政县| 永春县| 武冈市| 丽水市| 忻州市| 东城区| 彰化市| 乃东县| 济源市| 收藏| 岳阳市| 静海县| 东平县| 大新县| 东丽区| 兰西县| 黄平县| 阳高县| 兴山县| 阿拉尔市| 普兰店市| 大邑县| 宾阳县| 新和县| 读书| 霍城县| 渝中区| 祁东县| 泰宁县| 徐州市| 丰镇市| 纳雍县| 临沂市| 昌黎县| 高要市| 道孚县| 建宁县|