七、虚拟存储

虚拟存储的基本思想:
    一个进程的代码、数据、堆栈总量可能超过物理内存容量,OS复制把当前用到的部分留在内存中,把其他部分放在磁盘上(swap区)。当需要用到的某一部分不在内存中,则把暂时不用的写回磁盘,把需要的调入内存。
    进程直接产生的是虚拟地址,虚拟地址空间可能比物理内存大的多(不是和磁盘比较),虚拟地址在使用时先送到MMU,MMU把映射成的物理地址送到内存总线。内存和磁盘间的数据交换以页为单位,虚拟地址的页需要映射到物理地址中页帧,页未被映射的内容存于磁盘,present bit表示该页在不在内存上。当进程访问未映射的页时产生缺页失效,进入缺页中断,OS根据一定算法写回页和把需要访问的页写入页帧。虚拟内存的页无需在物理内存中保持特定的顺序。

页表
这里写图片描述
    32为系统当页大小为4K将有2^20个页,可以使用三级页表2^7 * 2^7 * 2^6,一级把4G空间分成128个32M,二级把32M分成128个256K,三级把256K分成64个4K。32位系统中大多数进程用到的虚拟地址空间只是4G空间的一小部分(最低端存放代码,最高端存放堆栈),其余大部分用不到。所以除了顶级页表和若干二、三级页表,中间的很多二、三级页表都不需要装入内存。
这里写图片描述
    页表项的每个条目包含权限控制、存在、修改、访问位等。
这里写图片描述
    页表如果都存在内存每个指令的内存操作都要进行查表,页表访问将影响系统效率。使用TLB(转译后备缓冲)它的访问速度比物理内存快,在TLB中存储最近访问过的页表项。

Linux虚拟内存管理
    当命令执行时,可执行的命令文件被打开,同时其内容被映射到进程的虚拟内存。这些操作通过修改描述进程内存映像的数据结构来完成,称为内存映射。只有映像的起始部分调入内存,其余部分仍留在磁盘。
    为了将虚拟地址转换成物理地址,处理器必须依次得到每级页表包含的偏移值。还需要有页目录在物理内存中的起始地址,该地址保存在寄存器中。

  • 处理器首先根据页目录在物理内存中的起始地址和第一个偏移值(虚拟地址中),访问页目录。得到中间页目录的起始地址。
  • 然后根据中间目录的起始地址和第二个偏移值,访问中间页目录,得到页表的起始地址
  • 再根据页表的起始地址和第三个偏移值访问页表,得到页帧号
  • 最后根据页帧号和页内偏移得出物理地址

linux/include/asm-i386/pgtable-3level.h

  • 该文件中定义三层页表相关宏

linux/include/linux/sched.h

  • linux启动一个新进程则为其分配一个task_struct结构体
  • 该结构体中包含指向mm_struct的结构体指针,mm_struct包含了用户进程和存储管理有关的信息
struct mm_struct {
    struct vm_area_struct * mmap;       /* 虚存结构链表 */
    rb_root_t mm_rb;                        /* 虚存构成的红黑树 */
    struct vm_area_struct * mmap_cache; /* last find_vma result */
    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 rw_semaphore mmap_sem;
    spinlock_t page_table_lock;     /* Protects task page tables and mm->rss */

    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_address;

    unsigned dumpable:1;

    /* Architecture-specific MM context */
    mm_context_t context;
};

程序执行时,可执行映像的内容被调入进程虚拟地址空间(没有调入物理内存,仅仅是连接到进程的虚拟地址)

  • struct mm_struct第一项struct vm_area_struct 指针指向的结构(多个由链表串起来)描述了虚拟内存的起始和结束地址,进程对次内存的存取权限以及一组内存操作函数。

struct vm_area_struct
- 每个struct vm_area_struct数据结构表示可执行映像的一部分:可执行代码、初始化数据、未初始化数据等待。
- 进程虚拟空间的0-3GB可以直接使用,剩余的1GB属于内核。在创建用户进程时,核心代码段和数据段被映射到3GB以后的虚拟空间,供内核使用。所有进程的3-4GB虚拟空间的映像都是相同的。

//linux/include/linux/mm/h
struct vm_area_struct {
    struct mm_struct * vm_mm;   /* The address space we belong to. */
    unsigned long vm_start;     /* Our start address within vm_mm. */
    unsigned long vm_end;       /* The first byte after our end address
                       within vm_mm. */

    /* linked list of VM areas per task, sorted by address */
    struct vm_area_struct *vm_next;

    pgprot_t vm_page_prot;      /* Access permissions of this VMA. */
    unsigned long vm_flags;     /* Flags, listed below. */

    rb_node_t vm_rb;

    /*
     * For areas with an address space and backing store,
     * one of the address_space->i_mmap{,shared} lists,
     * for shm areas, the list of attaches, otherwise unused.
     */
    struct vm_area_struct *vm_next_share;
    struct vm_area_struct **vm_pprev_share;

    /* Function pointers to deal with this struct. */
    struct vm_operations_struct * vm_ops;

    /* Information about our backing store: */
    unsigned long vm_pgoff;     /* Offset (within vm_file) in PAGE_SIZE
                       units, *not* PAGE_CACHE_SIZE */
    struct file * vm_file;      /* File we map to (can be NULL). */
    unsigned long vm_raend;     /* XXX: put full readahead info here. */
    void * vm_private_data;     /* was vm_pte (shared mem) */
};

mem_map_t描述每个物理页面,启动时初始化,内容记录页面的年龄、物理页帧号

//linux/include/linux/mm/h
typedef struct page {
    struct list_head list;      /* ->mapping has some page lists. */
    struct address_space *mapping;  /* The inode (or ...) we belong to. */
    unsigned long index;        /* Our offset within mapping. */
    struct page *next_hash;     /* Next page sharing our hash bucket in
                       the pagecache hash table. */
    atomic_t count;         /* Usage count, see below. */
    unsigned long flags;        /* atomic flags, some possibly
                       updated asynchronously */
    struct list_head lru;       /* Pageout list, eg. active_list;
                       protected by pagemap_lru_lock !! */
    wait_queue_head_t wait;     /* Page locked?  Stand in line... */
    struct page **pprev_hash;   /* Complement to *next_hash. */
    struct buffer_head * buffers;   /* Buffer maps us to a disk block. */
    void *virtual;          /* Kernel virtual address (NULL if
                       not kmapped, ie. highmem) */
    struct zone_struct *zone;   /* Memory zone we are in. */
} mem_map_t;

include/linux/mmzone.h

-zone_t中有一个free_area_t数组
- 数组元素0维护1个页面大小的空闲块的链表
- 元素2维护2^2=4个页面大小的空闲块链表
- free_list表示队列头
- map是每一块是否空闲的标志,如第N块空闲则第N位置位
页面分配
从free_area数据结构的free_list域着手沿链表搜索空闲块,如果某一个链表没有空闲块,则继续在下一个元素维护的链表中搜索。如果找到的空闲块不小于请求块的两倍,则将其分割成两部分,一部分分配一部分放入上个链表。

typedef struct free_area_struct {
    struct list_head    free_list;
    unsigned long       *map;
} free_area_t;

typedef struct zone_struct {
    /*
     * Commonly accessed fields:
     */
    spinlock_t      lock;
    unsigned long       free_pages;
    unsigned long       pages_min, pages_low, pages_high;
    int         need_balance;

    /*
     * free areas of different sizes
     */
    free_area_t     free_area[MAX_ORDER];

    /*
     * Discontig memory support fields.
     */
    struct pglist_data  *zone_pgdat;
    struct page     *zone_mem_map;
    unsigned long       zone_start_paddr;
    unsigned long       zone_start_mapnr;

    /*
     * rarely used fields:
     */
    char            *name;
    unsigned long       size;
} zone_t;

按需调页

  • arch/i386/mm/fault.c
  • 缺页中断会进入do_page_fault函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值