前言
上一篇解釋了內存的整個流程。內核供給,用戶使用,但是具體細節沒有細說,這裏我給出詳細的解釋。內核的供給也是一個挺複雜的問題。暫時我還沒搞懂,只好慢慢的邊看邊記錄。
正文
因爲linux是支持多處理器的,所以會有不同cpu,不同內存的問題。也就是不平整內存模式,我們不能像處理一個cpu的模式下處理那3g內存和兩個cpu的內存一樣,我們最好不要把一個數據結構分成兩部分存儲,一部分存在那個cpu的內存,一部分存在這個cpu的內存中。爲了處理這個問題。我門只好在原來的page的基礎上搞出一個數據結構,用來存放當前操作系統的所有的不同介質上的內容。
這裏是一個pglist_data數據結構。
typedef struct pglist_data {
zone_t node_zones[MAX_NR_ZONES]; //每個連續的存儲區,最多分爲三個區域,(這個先不解釋)
zonelist_t node_zonelists[NR_GFPINDEX]; //這貨是爲了分配時候準備的,也就是上面說那個區域的排序
struct page *node_mem_map;
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 pglist_data *node_next; //這裏是爲了維護一個單向隊列,畢竟不知一個連續存儲區。
} pg_data_t;
這貨比較複雜,但是我僅僅看出這三個參數的意義。其他暫時沒發現。以後總結。
其實大家還是很迷茫這是啥。最關鍵的是安格zone_t,我們看下
typedef struct zone_struct {
spinlock_t lock; //鎖
unsigned long offset; //一個特定的page數組的下標值。
unsigned long free_pages; //空閒page的個數,爲了分配
unsigned long inactive_clean_pages; //已經進入交換區的page
unsigned long inactive_dirty_pages; //每有進入交換區的page
unsigned long pages_min, pages_low, pages_high; //細節。
struct list_head inactive_clean_list; //已經進入交換區的page的list
free_area_t free_area[MAX_ORDER]; //這個是用來分配連續頁面用的。MAX_ORDER =10;
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;
真正用來存放頁面的是在free_area[MAX_ORDER]裏面,那我們繼續找free_area_t,
typedef struct free_area_struct {
struct list_head free_list; //這個就是連接page的結構
unsigned int *map;
} free_area_t;
既然可以連接page,那麼page一定有個list_head,我們來看下page結構
typedef struct page {
struct list_head list;
struct address_space *mapping;
unsigned long index;
struct page *next_hash;
atomic_t count;
unsigned long flags; /* atomic flags, some possibly updated asynchronously */
struct list_head lru;
unsigned long age;
wait_queue_head_t wait;
struct page **pprev_hash;
struct buffer_head * buffers;
void *virtual; /* non-NULL if kmapped */
struct zone_struct *zone;
} mem_map_t;
終於我們找到我們的page了,其實page的結構對於整個邏輯理解不會產生很大的偏差,這裏不再詳細註釋。總之就是可以通過pg_data_t整個鏈表找到我門的page。整體結構如圖
關於內核管理內存的供給,那麼進程對於內存的尋求也需要管理,我們的進程就像是佔據整個操作系統一樣(3g內存都是我的)。
在進程管理自己內存的時候。是需要幾個數據結構。我們知道每個進程都有一個結構專門用來維護自己信息的結構task_struct,這個很複雜,就不細說。裏面有個結構叫mm,類型中是
struct mm_struct {
struct vm_area_struct * mmap; //這是維護一個線性隊列,vm_area_struct,這個纔是最終的內存區間信息
struct vm_area_struct * mmap_avl; //數據過多。線性隊列不行,就用avl樹來維護。可以平衡搜說時間
struct vm_area_struct * mmap_cache; //上次使用的vm_area_struct
pgd_t * pgd;
atomic_t mm_users; /* How many users with user space? */
atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */
int map_count; /* number of VMAs */
struct semaphore mmap_sem;
spinlock_t page_table_lock;
struct list_head mmlist; /* List of all active mm's */
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; /* number of pages to swap on next pass */
unsigned long swap_address;
/* Architecture-specific MM context */
mm_context_t context;
};
中文註釋中其實一切都是爲了vm_area_struct,我們繼續看看vm_area_struct
struct vm_area_struct {
struct mm_struct * vm_mm; /* 上一層結構 */
unsigned long vm_start; //這纔是關鍵。開始虛擬地址開始
unsigned long vm_end; //結束
struct vm_area_struct *vm_next; //vm_area_struct單向對列靠你來
pgprot_t vm_page_prot;
unsigned long vm_flags;
/* AVL 樹的資料 */
short vm_avl_height;
struct vm_area_struct * vm_avl_left;
struct vm_area_struct * vm_avl_right;
struct vm_area_struct *vm_next_share;
struct vm_area_struct **vm_pprev_share;
struct vm_operations_struct * vm_ops;
unsigned long vm_pgoff; /* offset in PAGE_SIZE units, *not* PAGE_CACHE_SIZE */
struct file * vm_file;
unsigned long vm_raend;
void * vm_private_data; /* was vm_pte (shared mem) */
};
這裏面有幾個關於文件的信息,這是爲了mapping,或者交換時候使用,對於真個內存管理原理影響不大。可以忽視。結構如圖:
下面說寫幾個函數,加強些記憶。
//找vm_area_struct,這裏當然循環查找那個線性對列或者avl樹
struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
//插入數據到線性對列或者avl樹,這裏細節就不寫了。
void __insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
後記
這裏無論是從內核空間和用戶空間都完成了對於page的管理。但是真正的難題還是在具體操作,並且這些概念貌似比較容易理解,但是最難的是如何利用這些數據結構,來處理具體的問題。以後我們慢慢的來解決具體問題。