關於linux內存管理的主要數據結構

前言

上一篇解釋了內存的整個流程。內核供給,用戶使用,但是具體細節沒有細說,這裏我給出詳細的解釋。內核的供給也是一個挺複雜的問題。暫時我還沒搞懂,只好慢慢的邊看邊記錄。

正文

因爲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的管理。但是真正的難題還是在具體操作,並且這些概念貌似比較容易理解,但是最難的是如何利用這些數據結構,來處理具體的問題。以後我們慢慢的來解決具體問題。

發佈了66 篇原創文章 · 獲贊 29 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章