关于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的管理。但是真正的难题还是在具体操作,并且这些概念貌似比较容易理解,但是最难的是如何利用这些数据结构,来处理具体的问题。以后我们慢慢的来解决具体问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值