• 【操作系统】进程空间管理


    用户态与内核态的划分

    • 进程的虚拟地址空间,就是换了个角度看内存。
    • 整个虚拟内存要一分为二, 一部分是内存态地址空间,一部分是内核态的内存空间
    • 32位系统,最大寻址是2^32 = 4G,其中用户态虚拟地址空间是3G, 内核态是1G。
    • 64位系统,虚拟地址只使用了 48位, 1 >> 47 相当于 47 ^2 ,也就是内核态和用户态各自拥有128T.
      在这里插入图片描述

    用户态的布局

    unsigned long mmap_base;	/* base of mmap area */
    unsigned long total_vm;		/* total_vm 是总共映射的页的数目 */
    unsigned long locked_vm;	/* Pages that have PG_mlocked set */
    unsigned long pinned_vm;	/* Refcount permanently increased */
    unsigned long data_vm;		/* VM_WRITE & ~VM_SHARED & ~VM_STACK */
    unsigned long exec_vm;		/* VM_EXEC & ~VM_WRITE & ~VM_STACK */
    unsigned long stack_vm;		/* VM_STACK */
    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • total_vm 是总共映射的页的数目,内存吃紧的时候,locked_vm 就是被锁定不能换出,pinned_vm 是不能换出,也不能移动。 换出 : 把内存写到硬盘

    • data_vm 是存放数据的页的数目,exec_vm 是存放可执行文件的页的数目,stack_vm 是栈所占的页的数目。

    • start_code 和 end_code 表示可执行代码的开始和结束位置,start_data 和 end_data 表示已初始化数据的开始位置和结束位置。

    • start_brk 是堆的起始位置,brk 是堆当前的结束位置。前面咱们讲过 malloc 申请一小块内存的话,就是通过改变 brk 位置实现的。

    • start_stack 是栈的起始位置,栈的结束位置在寄存器的栈顶指针中。

    • arg_start 和 arg_end 是参数列表的位置, env_start 和 env_end 是环境变量的位置。它们都位于栈中最高地址的地方

    • mmap_base 表示虚拟地址空间中用于内存映射的起始地址。这个空间是从高地址到低地址增长的。
      在这里插入图片描述

    • 这里用红黑树,就是为了快速查找一个内存区域,并在需要改变的时候,能够快速修改

    • anoy 就是 anonymous,匿名的意思,映射到文件就需要有 vm_file 指定被映射的文件。

    • 当 exec 运行一个二进制程序的时候,除了解析 ELF 的格式之外,另外一个重要的事情就是建立内存映射。
      在这里插入图片描述

    • 内存映射图 :
      在这里插入图片描述

    • 下面这俩种情况都会修改上面的映射关系

    • 第一种情况是函数的调用,涉及函数栈的改变,主要是改变栈顶指针。

    • 第二种情况是通过 malloc 申请一个堆内的空间,当然底层要么执行 brk,要么执行 mmap。关于内存映射的部分。

    • brk (堆) : 堆是从低地址向高地址增长的, 会有新旧的brk堆顶地址, 需要比较,如果俩者相同的话,则说明在同一页,则修改堆顶地址就行,指向新的地址, 如果新的 < 旧的 则说明不在一页,至少需要释放一页。

      • brk 判断是否需要分配新页, 并做对应操作; 需要分配新页时需要判断能否与其他 vm_area_struct 合并

    内核态的布局

    32 位
    在这里插入图片描述
    64位
    在这里插入图片描述

    小结

    • 内存管理信息在 task_struct 的 mm_struct 中
    • task_size 指定用户态虚拟地址大小
      • 32 位系统:3G 用户态, 1G 内核态
      • 64 位系统(只利用 48 bit 地址): 128T 用户态; 128T 内核态
    • 用户态地址空间布局和管理
      • mm_struct 中有映射页的统计信息(总页数, 锁定页数, 数据/代码/栈映射页数等)以及各区域地址
      • 有 vm_area_struct 描述各个区域(代码/数据/栈等)的属性(包含起始/终止地址, 可做的操作等), 通过链表和红黑树管理
      • 在 load_elf_bianry 时做 vm_area_struct 与各区域的映射, 并将 elf 映射到内存, 将依赖 so 添加到内存映射
      • 在函数调用时会修改栈顶指针; malloc 分配内存时会修改对应的区域信息(调用 brk 堆; 或调用 mmap 内存映射)
      • brk 判断是否需要分配新页, 并做对应操作; 需要分配新页时需要判断能否与其他 vm_area_struct 合并
    • 内核地址空间布局和管理
      • 所有进程看到的内核虚拟地址空间是同一个
      • 32 位系统, 前 896MB 为直接映射区(虚拟地址 - 3G = 物理地址)
        • 直接映射区也需要建立页表, 通过虚拟地址访问(除了内存管理模块)
        • 直接映射区组成: 1MB 启动时占用; 然后是内核代码/全局变量/BSS等,即 内核 ELF文件内容; 进程 task_struct 即内核栈也在其中
        • 896MB 也称为高端内存(指物理内存)
        • 剩余虚拟空间组成: 8MB 空余; 内核动态映射空间(动态分配内存, 映射放在内核页表中); 持久内存映射(储存物理页信息); 固定内存映射; 临时内存映射(例如为进程映射文件时使用)
      • 64 位系统: 8T 空余; 64T 直接映射区域; 32T(动态映射); 1T(物理页描述结构 struct page); 512MB(内核代码, 也采用直接映射)
        32位
        在这里插入图片描述
        64位
        在这里插入图片描述
  • 相关阅读:
    Flutter实战-请求封装(四)之gzip报文压缩
    CRLF,URL重定向,Web拒绝服务
    [BMIm]BF4离子液体修饰的铜纳米粒子直径小于10nm
    数据结构:队列
    Unity中Commpont类获取子物体的示例
    用一个简单的例子说面向对象和面向过程的区别
    py2_Python 3 的六大数据类型
    rust 迭代器
    前端 vue 项目屏蔽右键
    60页政务大数据资源 平台项目可研方案 2022(转发下载)
  • 原文地址:https://blog.csdn.net/weixin_49486457/article/details/125900942