這裏只列舉幾個比較麻煩的數據結構
struct list_head {
struct list_head *next, *prev;
} //linux通用的雙向鏈隊列,下面多處用到,這裏列出源代碼
linux對內存再用頁式管理,對於頁,就有個數據結構page加以描述。在內核中有個全局量mem-map指向的是一個page的數組,整個數組描述了整個物理內存,你們注意32位地址線,內存大小是2的32次方。因爲頁大小是4k也就是2的12次方。每4K的頁就有一個page。那麼2的32次方共有2的20次方個頁,則mem-map指向的數組大小就是2的20次方。其中明顯對於頁的物理地址,必定是4K的倍數,由於它大小是4K,那麼這個數組就有個對應,數組下標後面12個0(2進制)對應了頁面的物理地址,他們在數值上是相等的。那麼咱們在page數據結構中就沒有必要存貯它的物理地址。page數據結構定義位置include/linux/mm.h
struct page{
struct list_head list; //經過使用它進入下面的數據結構free_area_struct結構中的雙向鏈隊列
struct address_space * mapping; //用於內存交換的數據結構
unsigned long index;//當頁面進入交換文件後
struct page *next_hash; //自身的指針,這樣就能夠連接成一個鏈表
atomic t count; //用於頁面交換的計數,若頁面爲空閒則爲0,分配就賦值1,沒創建或恢復一次映射就加1,斷開映射就減一
unsigned long flags;//反應頁面各類狀態,例如活躍,不活躍髒,不活躍乾淨,空閒
struct list_head lru;
unsigned long age; //表示頁面壽命
wait_queue_head_t wait;
struct page ** pprev_hash;
struct buffer_head * buffers;
void * virtual
struct zone_struct * zone; //指向所屬的管理區
}
(對於每一個項的說明,我會慢慢補上)
對內存,僅僅用page數據結構來描述確定遠遠不夠,對於整個內存,咱們在此之上分了管理區的概念,每一個管理區管理數個頁面。這個數據結構是 zone_struct定義位置是在include/linux/mmzone.h
typedef struct free_area_struct {
struct list_head free_list; //linux 中通用的雙向鏈隊列
unsigned int * map;
} free_area_t;
typedef struct zone_struct{
spinlock_t lock;
unsigned long offset; //表示該管理區在mem-map數組中,起始的頁號
unsigned long free pages;
unsigned long inactive_clean_pages;
unsigned long inactive_dirty_pages;
unsigned pages_min, pages_low, pages_high;
struct list_head inactive_clean_list; //用於頁面交換的隊列,基於linux頁面交換的機制。這裏存貯的是不活動「乾淨」頁面
free_area_t free_area[MAX_ORDER];
//一組「空閒區間」隊列,free_area_t定義在上面,其中空閒下標表示的是頁面大小,例如:數組第一個元素0號,表示全部區間大小爲2的0次方的頁面連接成的雙向隊列,1號表示全部2的1次方頁面連接連接成的雙向隊列,2號表示全部2的2次方頁面連接成的隊列,其中要求是這些頁面地址連續
char * name;
unsigned long size;
struct pglist_data * zone_pgdat; //用於指向它所屬的存貯節點,及下面的數據結構
unsigned long zone_start_paddr;
unsigned long zone_start_mapnr;
struct page * zone_mem_map;
} zone_t;
咱們知道內存的地位並非「平等的」,例如主內存和圖形卡上的靜態內存ram就不是「平等地位」,所以咱們頁面管理機制作了修正,管理區不是內存管理中最高層的概念,前述的page數組mem-map也不是全局,而是從屬於具體的節點,在zone_struct 上面有了一層表明存貯節點的數據結構pglist_data,定義於include/linux/mmzone.h 中
typedef struct pglist_data {
zone_t node_zones[MAX_NR_ZONES]; //該節點最多的3個頁面管理區,MAX_NR_ZONE值是3,在linux中分爲3個管理區,也多是2個ZONE_DMA,ZONE_NORMAL,ZONE_HIGHMEM
zonelist_t node_zonelist[NR_GFPINDEX]; //具體說明見下面的數據結構
struct page * node_mem_map; //用於指向屬於該存儲節點的page數組
unsigned long * valid_addr_bitmap;
struct bootmem_data * bdata;
unsigned long node_start_paddr;
unsigned long node_start_mapnr;
unsigned long node_size;
int node_id;
struct pglistdata * node_next; //用於造成一個單鏈隊列
} pg_data_t;
typedef struct zonelist_struct {
zone_t * zones [MAX_NR_ZONES+1]; //指針數組,指向每一個具體的頁面管理區
int gfp_mask;
} zonelist_t; //用於描述內存分配策略的數據結構,好比內存中最小適應法則的分配策略,咱們就能夠將區放入zones數組中,按照區內空閒頁面從小到大的原則,但咱們要實現這個法則,咱們只須要從頭至尾便利這個數組,那麼找到第一個大於你要求的頁面個數的區就是最小適應區
這些都是用於物理空間管理的,虛擬空間管理由下面的數據結構描述(我剛開始把虛擬空間弄成了虛擬內存,越看越糊塗,虛擬空間指的是,在linux中,4G內存被分爲2塊,搞地址1G內存叫系統空間,全部進程共享,下面的3G即是虛擬空間,每一個進程都佔有虛擬空間3G,在進程本身看來是這樣的,但實際上,他遠遠沒這麼多內存用),vm_area_struct數據結構,定義於 include/linux/mm.h,進程虛存空間的描述,他被進一步組織到mm_struct中,它描述是地址連續的空間
struct vm_area_struct {
struct mm_struct * vm_mm; //下面說明
unsigned long vm_start;
unsigned long vm_end; //start和end決定了虛存空間,我的理解應該是mem-map表的下標,其中 start包含,end不包含,同時區間劃分不僅僅是地址連續,還要保證權限的統一
struct vm_area_struct * vm_next; //將屬於同一進程的虛存區間按照虛存地址高低連接起來
pgrot t_vm_page_prot;
unsigned long vm_flags; //存貯該區間的權限
short vm_avl_height;
struct vm_area_struct * vm_avl_left;
struct vm_area_struct * vm_avl_rigth; //用於生成 avl樹,提升搜索效率
struct vm_area_struct * vm_next_share;
struct vm_area_struct ** vm_pprev_share;
struct vm_operations_struct * vm_ops; //下面說明
unsigned long vm_pgoff;
struct file * vm_file;
unsigned long vm_raend;
void * vm_private_data; //這些屬性都是用於記錄頁面與文件關係,具體狀況具體分析
}
定義於include/linux/mm.h
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);
} //open, close,nopage用於虛存空間打開,關閉和創建印射
定義於include/linux/sched.h,進程全部的虛存空間的數據結構描述
struct mm_struct{
struct vm_area_struct * mmap; //創建虛存空間的單鏈隊列
struct vm_area_struct * mmap_avl; //創建虛存空間的AVL樹
struct vm_area_struct * mmap_cache; //最近一次使用的虛存空間,因爲內存訪問老是帶有局部性,命中率有35%
pgd_t * pgd; //指向進程頁面目錄,在載入進程時候這個值會被載入到cr3寄存器中
atomic_t mm_users;
atomic_t mm_count;
//這2個變量比較使人費解,mm_users記錄是虛存空間的使用者,而mm_count記錄的是mm_struct使用的計數。首先虛存空間是能夠多個進程使用的,好比若是父進程調用vfork建立子線程,此時2者使用的是同一個虛存空間。線程是沒有本身的虛存空間。其次一個mm_struct對應一個虛存,有幾個使用者那麼就有幾個進程經過指針共享了這個mm_struct,按理說這2個計數應該是一個,不該該分紅2個。大部分可能性2者是相同的。但又特殊狀況,好比內核線程是沒有虛存空間,他是須要暫借調用者的虛存空間,只是虛存空間使用者和mm_struct使用計數就不統一
int map_count;
struct semaphore mmap_sem; //用於進程的間的互斥訪問
spinlock_t page_table_lock;
struct list_head mmlist;
unsigned long start_code, end_code, start_data, end_data
unsigned long start_brk, brk, start_stack;
unsigned long arg_start, arg_end, env_start, env_end;
unsigned long rss, total_vm, locked_vm;
unsigned long def_flags;
unsigned long cpu_vm_mask;
unsigned long swap_cnt;
unsigned long swap_address;
mm_context_t context;
}
在操做系統中,有個進程控制塊(PCB)的概念,具體到linux裏面對應的數據結構是task_struct,它內部就有個mm_struct指針,mm_struct是整個用戶空間的抽象。待續。。。