当前位置:首页 > 行业动态 > 正文

Linux 虚拟存储是如何工作的?

linux 虚拟存储是一种技术,它通过软件模拟的方式将物理存储资源抽象化,为用户提供一个统一的、灵活的存储空间。这种技术可以优化存储资源的使用,提高系统的性能和可靠性。

Linux 虚拟存储

Linux 虚拟存储是如何工作的?  第1张

一、Linux 虚拟存储

Linux 操作系统中的虚拟存储管理机制是现代计算机系统的重要组成部分,虚拟存储的概念是为了解决物理内存的限制,通过将磁盘空间作为扩展内存使用,使得进程能够运行比实际物理内存更大的程序,Linux 采用段页式存储管理来实现这一目标,结合了分段和分页的优点,实现了高效灵活的内存管理。

二、虚拟存储器

在实存储器管理模式中,要求作业在运行前全部装入内存,之后就一直驻留在内存中直到运行结束,这种方式会导致内存资源的浪费,因为某些程序并没有一直处于运行状态,却长期占用着内存资源,为了提高内存利用率,引入了虚拟存储器。

虚拟存储器并不以物理的方式存在,而是从逻辑上对内存容量进行扩充,提供了一个比真实内存空间大得多的逻辑地址空间的“逻辑存储器”,虚拟存储技术把用户地址空间和实际的存储空间区分开,在程序运行时通过动态重定位的地址映射机制将逻辑地址转换为物理地址。

动态重定位是指在目标程序执行过程中,在 CPU 访问内存之前,由硬件地址映射机构完成将指令或数据的逻辑地址向物理地址的转换,由于这种地址转换是在程序执行期间随着每条指令的数据访问自动连续地进行,因此称为“动态重定向”。

在386保护模式下,Linux可以提供的逻辑地址空间为4GB,全局描述符表定义了如何分配逻辑地址空间:0GB 3GB为用户空间,用户进程可以直接访问;3GB 4GB为内核空间,用户进程不能直接访问。

三、段页式存储管理

Linux中的内存管理技术采用的是段页式虚存技术,它将一个进程中的程序、数据、堆栈分成若干“段”来处理,每段有一个8字节的段描述符,指出该段的起始地址、长度和存取权限等信息,这些段描述符的集合构成段描述符表,通过一个寄存器指出该表的起始位置,为了便于段长的动态变化,每段分为若干页,将需要的内容以页面为单位调入内存的物理块中,暂不执行的页面仍留在外存,以保证比实际内存容量需求更大的进程能够正常使用内存。

1. Linux的分段机制

Linux的分段机制就是将线性地址空间分段,利用这些段来存储代码和数据,通过对段的保护来提供一种对数据或代码的保护,根据每个段的作用和存储内容的不同,分为三类进程段:代码段、数据段和堆栈段;两类系统段:TSS段(任务状态段)和LDT段(局部描述符表段)。

在保护模式下,逻辑地址空间可达4GB,从逻辑地址到线性地址的转换由分段机制管理,段寄存器CS、DS、ES、SS、FS或GS标识一个段,这些段寄存器作为段选择器,用来选择该段的描述符。

进程使用的是48位的逻辑地址,其中高16位是段选择符,低32位是段内的偏移量,通过段选择符在GDT(全局描述符表)或LDT(局部描述符表)中索引相应的段描述符,以得到该段的基地址,再加上偏移量得到逻辑地址对应的线性地址,然后通过分页地址的转换,将线性地址转换为物理地址,最后通过物理地址访问内存。

2. Linux的分页机制

分页机制是在段机制之后进行的,它进一步将线性地址转换为物理地址,Linux一般使用4K字节大小的页(PAGE_SIZE,include/linux/page.h,通过修改PAGE_SHIFT定义的左移位数来修改页面大小),且每页的起始地址都被4K整除,Linux把4GB的线性地址空间划分为1M个页面,采用了两级表结构。

页目录:第一级表称为页目录,存储在一个4K字节的页中,页目录表共有1K个表项,每个表项为4个字节,线性地址最高的10位(22-31位)用来产生第一级表索引,由该索引得到的表项中的内容定位二级表中的一个表的地址,即下级页表所在的内存块号。

页表:第二级表称为页表,存储在一个4K字节页中,它包含了1K字节的表项,每个表项包含了一个页的物理地址,二级页表由线性地址的中间10位(12-21位)进行索引,定位页表表项,获得页的物理地址,页物理地址的高20位与线性地址的低12位形成最后的物理地址。

四、Linux进程与段页式管理

每当启动一个新的进程,Linux都为其创建一个进程控制块(task_struct, include/linux/sched.h),在创建过程中,每个进程(根据需要)创建并初始化新页目录,设置页目录基地址寄存器,在GDT中添加进程对应的TSS项和LDT项,创建并初始化该进程的LDT。

Linux采用“按需调页”的原则来分配内存页面,执行进程的页面总会在外存与内存之间不断交换,从而避免页表过多占用存储空间,创建一个进程时页面分配的情况大致是这样的:进程控制块(1页),内存态堆栈(1页),页目录(1页),页表(需要的n页),在进程以后执行的过程中,再根据需要逐渐分配更多的内存页面。

五、Linux交换空间

交换空间是在外存中开辟一定的空间来临时存放从内存中调出的页面,其存储区域自然也是按页划分的,Linux采用了块设备和交换文件两种形式来保存换出的页面,但是这两种形式的内部结构是一致的,为了优化系统性能,会定义不止1个交换空间,因而Linux实现了并行管理多个交换空间,这些交换空间均定义在同一个数据结构中(swap_info_struct[MAX_SWAPFILES], mm/swap.c,其中MAX_SWAPFILES定义为最大的交换空间数量)。

六、Linux虚存管理的数据结构模型

根据虚拟内存抽象模型,每个进程都可以互不干扰的使用所有虚拟地址,进程的虚拟内存空间被划分为小的虚拟内存区域来使用,每个内存区域是一段具有相同属性的虚拟地址空间,Linux用vm_area_struct(include/linux/mm.h)表示一个连续的虚拟内存区域。

1. vm_area_struct结构体

struct vm_area_struct {
    unsigned long vm_start;    /* Our start address within vm_mm */
    unsigned long vm_end;      /* The first byte after our end address within vm_mm */
    pgprot_t vm_page_prot;     /* Access permissions of this VMA. */
    unsigned short vm_flags;   /* Flags, see mm.h for details */
    struct rb_node vm_rb;     /* Red-black tree linkage. */
    /* Linkage into the list of vma heads for the address space */
    struct list_head vm_list;
    struct mm_struct *vm_mm;    /* Owner of */
    /* A file backed memory map? We use a doubly linked list for that */
    struct vm_area_struct *vm_next_share; /* Share with another process if != NULL */
    struct vm_area_struct **vm_pprev_share; /* Previous in chain of */
    pgoff_t vm_pgoff;        /* Offset (within vm_file) at which to start syncing CoW ptes */
    struct file *vm_file;       /* File we map to (can be NULL). */
    void *vm_private_data;     /* Was vm_pte (shared mem). */
};

2. 主要字段解释

vm_start: 虚拟内存区的起始虚拟内存地址。

vm_end: 虚拟内存区的结束虚拟地址(不包括)。

vm_page_prot: 当前虚拟内存区所映射的物理内存页的读写权限。

vm_flags: 当前虚拟内存区的标志。

vm_rb: 红黑树节点结构,用于加速查找过程。

vm_list: 链表节点结构,用于链接所有的虚拟内存区域。

vm_mm: 指向进程的内存管理对象mm_struct。

vm_next_share: 与其他进程共享此虚拟内存区域时的指针。

vm_pprev_share: 共享链表中的前一个指针。

vm_pgoff: 文件中的偏移量(如果此VMA映射到文件)。

vm_file: 此VMA映射到的文件(可以为NULL)。

vm_private_data: 私有数据指针。

3. 红黑树与链表

Linux通过红黑树和链表两种数据结构来管理这些虚拟内存区域,红黑树用于快速查找,链表则用于线性遍历,每个进程都有一个独立的红黑树和链表。

七、Linux虚存管理的主要数据结构之间的关系

1. mm_struct结构体

struct mm_struct {
    pgd_t *pgd;          // Page global directory (页全局目录)
    atomic_t mm_users;   // Ref count (引用计数)
    atomic_t mm_count;   // Number of times structure is pinned (结构固定的次数)
    int map_count;       // Number of VMAs (虚拟内存区域的数量)
    spinlock_t page_table_lock; // Lock for page tables and VMAs (页表和虚拟内存区域的锁)
    struct rw_semaphore mmap_sem; // Semaphore for changing map count (改变映射计数的信号量)
    struct list_head mmlist; // List of all mm_structs (所有mm_struct的列表头)
    struct task_struct *owner; // Owner task struct (拥有者的任务结构)
};

2. 主要字段解释

pgd: 页全局目录的指针。

mm_users: 引用计数。

mm_count: 结构固定的次数。

map_count: VMA的数量。

page_table_lock: 页表和VMA的锁。

mmap_sem: 改变映射计数的信号量。

mmlist: 所有mm_struct的列表头。

owner: 拥有者的任务结构指针。

3. vm_area_struct与mm_struct的关系

vm_area_struct结构体中的vm_mm字段指向了mm_struct结构体,表示该虚拟内存区域所属的内存描述符,而mm_struct中的pgd字段则指向了页全局目录,通过这种关系,可以实现虚拟地址到物理地址的映射。

4. 红黑树与链表的关系

每个进程都有自己的红黑树和链表来管理其虚拟内存区域,红黑树用于快速查找某个虚拟地址对应的vm_area_struct结构体,而链表则用于线性遍历所有的虚拟内存区域,当插入一个新的vm_area_struct时,会同时插入到红黑树和链表中;删除时也会同时从红黑树和链表中移除。

Linux虚拟存储管理机制通过段页式存储管理技术有效地解决了物理内存不足的问题,使得进程能够运行比实际物理内存更大的程序,分段机制提供了对不同类型数据的隔离和保护,而分页机制则进一步提高了内存管理的灵活性和效率,通过虚拟内存区域(VMA)的管理,Linux实现了对进程地址空间的动态调整和优化,红黑树和链表等数据结构的应用则保证了虚拟内存区域操作的效率和正确性。

到此,以上就是小编对于“linux 虚拟存储”的问题就介绍到这了,希望介绍的几点解答对大家有用,有任何问题和不懂的,欢迎各位朋友在评论区讨论,给我留言。

0