• Linux:进程地址空间的简易认识



    全文约 2010 字,预计阅读时长: 7分钟


    进程地址空间

    验证地址空间的基本排布

    在这里插入图片描述

    • 代码验证:
    #include 
    #include 
    
    int g_unval;
    int g_val = 100;
    
    
    int main(int argc, char *argv[], char *env[])
    {
          printf("code addr         : %p\n", main);
        const char *p = "hello bit!";
        printf("read only         : %p\n", p);
        printf("global val        : %p\n", &g_val);
        printf("global uninit val : %p\n", &g_unval);
        char *q1 = (char *)malloc(10);
        char *q2 = (char *)malloc(10);
        char *q3 = (char *)malloc(10);
        char *q4 = (char *)malloc(10);
        printf("heap addr         : %p\n", q1);
        printf("heap addr         : %p\n", q2);
        printf("heap addr         : %p\n", q3);
        printf("heap addr         : %p\n", q4);
    
        int a = 0;
        static int b = 0;
        int c = 0;
        printf("stack addr        : %p\n", &p);
        printf("stack addr        : %p\n", &a);
        printf("b: stack addr        : %p\n", &b);
        printf("stack addr        : %p\n", &c);
    
        printf("args addr         : %p\n", argv[0]);
        printf("args addr         : %p\n", argv[argc-1]);
    
        printf("env  addr         : %p\n", env[0]);
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    址同值不同

    #include 
    #include 
    #include 
    
    int g_val = 0;
    int main()
    {
    	 pid_t id = fork();
    	 if(id < 0){
    	 perror("fork");
    	 return 0;
    	 }
     else if(id == 0){ //child
    		printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
     }else{ //parent
    		 printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
     }
    		 sleep(1);
     return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 得到,全局变量地址是相同的值,但看到的变量值是不一样的。

    定义

    • 地址空间是进程看待内存的方式,抽象出来的一个概念,内核下是一个结构体。这样每个进程,都认为自己独占系统内存资源。
    • 区域划分:将线性的地址空间或分成位一个个的地址区间【start,end】
    • 虚拟地址:在【start,end】之间的各个地址。
    • 地址空间通过页表在物理内存上进行映射,通过各种倒腾,保证有那么多进程可以运行。相关工作由操作系统完成。
    • 假设某个进程越界访问,则可以通过页表查看该段的读写权限,进行报错中断程序运行。
    • 父子进程一个数据的虚拟地址一样,呈现的数值不一样;是因为子进程的大部分信息,继承自父进程;进程管理这一侧,映射关系没变;但在内存管理那一侧,在物理内存上又开辟了一块儿空间给子进程使用。
      在这里插入图片描述
    • 为什么存在地址空间?
    • 保护物理内存,不受到任何进程内的地址的直接访问,方便合法性校验。
    • 将内存管理和进程管理解耦,内存只需看这块儿空间有没有被人用,不需要关心是谁在用。
    • 让进程,以同样的方式,来看待代码和数据。这个区是代码区,这个区是数据区等等…
    • 因此,一个进程被创建时,都有独自的PCB,进程地址空间、和页表。
      在这里插入图片描述

    可执行程序文件 vs 进程地址空间

    • 可执行程序本身,就已经被划分成了一个个的区域;方便模块化加载到内存和库文件的链接。

    • 两者的结构布局相呼应。
      在这里插入图片描述

    • 目标文件链接以后就是可执行;库代码的融合、库数据的融合等。

    在这里插入图片描述
    在这里插入图片描述


    内存管理

    在这里插入图片描述

    • 页框(page frame)是一个 内存管理 的概念定义。 是指 CPU 中添加了能自动把 虚拟内存 (即 逻辑地址 )地址转化为 物理内存 地址的电路,为了简化这种电路,就把 RAM 划分为 长度 为4KB或8KB的块。
      在这里插入图片描述

    操作系统下的进程与内存管理

    在这里插入图片描述
    在这里插入图片描述


    虚拟内存

    在这里插入图片描述

    • 进程中的所有内存访问都是逻辑地址,这些逻辑地址会在运行时动态地转换为物理地址。 这意味着一个进程可被换入或换出内存,因此进程可在执行过程的不同时刻占据内存中的不同区域。
    • 一个进程可划分为许多块(页和段),在执行过程中,这些块不需要连续地位于内存中。动态运行时地址转换和页表或段表的使用使得这一点成为可能。
      在这里插入图片描述
      在这里插入图片描述

    参考

  • 相关阅读:
    Vue create 之后的空架子完善
    React函数式组件 父组件调用子组件方法
    四、伊森商城 前端基础-Vue MVVM思想&Vue安装&单向绑定 p21
    【Java八股文总结】之JDK常见问题排查
    vue中的计算属性和监听属性
    昇腾AI与“紫东.太初”赋能法律服务,多模态大模型迈向“多专多能”
    低版本浏览器使用最新渲染模式以免IE不支持CSS3属性
    Automatically Generate a TOC for your PDF
    swift 【block】
    【阿里云】图像识别
  • 原文地址:https://blog.csdn.net/WTFamer/article/details/126020062