【Linux】程序地址空间

文章目录

  • 程序地址空间
    • 1. c/c++程序地址空间分布规则
    • 2. linux下观察
    • 3. 页表和MMU
    • 4. 缺页中断
    • 5. 写实拷贝

程序地址空间

【Linux】程序地址空间_第1张图片

1. c/c++程序地址空间分布规则

int unval;
int val = 100;
int main()
{
   const char *s ="hello world";//字符常量区
    printf("code addr: %p\n", main);//栈
    printf("string rdonly addr: %p\n", s);//字符常量区
    printf("uninit addr: %p\n", &unval);//未初始化
    printf("init addr: %p\n", &val);//已初始化
    char *heap = (char*)malloc(10);
    char *heap1 = (char*)malloc(10);
    char *heap2 = (char*)malloc(10);
    char *heap3 = (char*)malloc(10);
    char *heap4 = (char*)malloc(10);

    //堆区向高地址增加
    printf("heap addr: %p\n", heap1);
    printf("heap addr: %p\n", heap2);
    printf("heap addr: %p\n", heap3);
    printf("heap addr: %p\n", heap4);

    //栈区向低地址方向减少
    printf("stack addr: %p\n", &s);
    printf("stack addr: %p\n", &heap);
    int a = 10;
    int b = 30;
    printf("stack addr: %p\n", &a);
    printf("stack addr: %p\n", &b);
}

验证:

【Linux】程序地址空间_第2张图片


2. linux下观察

  9 int g_val = 100;
 10 
 11 int main()
 12 {
 13     //数据是各自私有一份(写时拷贝)
 14     if(fork() == 0){
 15         //child
 16         int cnt = 5;
 17         while(cnt){
 18             printf("I am child, times: %d, g_val = %d, &g_val = %p\n", cnt, g_val, &g_val);
 19             cnt--;
 20             sleep(1);
 21             if(cnt == 3){
 22                 printf("##################child更改数据#########################\n");
 23                 g_val = 200;
 24                 printf("##################child更改数据done#########################\n");
 25             }
 26         }
 27     }
 28     else{
 29         //parent
 30         while(1){
 31             printf("I am father, g_val = %d, &g_val = %p\n", g_val, &g_val);
 32             sleep(1);
 33         }
 34     }
 35     return 0;
 36 }   

【Linux】程序地址空间_第3张图片


如果是物理空间,相同的地址指向不同数值绝对不可能

我们c++/c或者别的语言使用的地址,不是物理地址,而是虚拟地址

每个进程创建的时候都要有一个struct mm_struct{}

虚拟地址,内核的一个数据结构,描述具体地址空间变量

struct mm_struct
{
    //低地址先定义
    unsigned int code_start;
    unsigned int code_end;
    
    unsigned int init_data_start;
    unsigned int init_data_end;
    
    unsigned int uninit_data_start;
    unsigned int uninit_data_end;
    
}

每个进程都认为自己拥有4g


3. 页表和MMU

MMU(memory manage unity)是一种硬件,用来查页表

页表将虚拟地址和物理地址进行一个映射的关系

如果直接在物理内存弄,遇到数组越界问题,会影响其他进程(例子1)

操作系统的给我们用户的权限只有r

  • 问题:我们申请1000字节,我们立马能使用
    1000个字节吗? ?(例子2)
  • 不一定,可能会存在暂时不会全部使用
    甚至暂时不使用!
  • 在0S角度,如果空间立马给你,是不是意味着,整个
    系统会有一部分空间,本来可以给别人立马用的,现在却被你浪费

例子3:通过列表,操作系统可以将进程的不同段的代码放在物理内存的不同地方,但在虚拟地址上它是个连续的空间


4. 缺页中断

对于上面的问题,操作系统先准备好虚拟地址,等进程真正需要使用的时候,在页表中申请物理内存并且对虚拟地址和物理地址进行映射关系的联系(反映了写实拷贝 )

此等待过程,称之为缺页中断,在操作系统内部发生


程序地址空间的含义:

  • (例子1)通过添加一层软件层,完成有效的对进程操作内存进行风险管理(权限管理),本质目的是为了,保护物理内存以及各个进程的数据安全!

  • (例子2)将内存申请和内存使用的概念在时间上划分清楚,通过虚拟地址空间,来屏蔽底层申请内存的过程,达到进程读写内存和0S进行内存管理操作,进行软件上面的分离

  • (例子3)站在CPU和应用层的角度,进程可以看做统一使用4GB空间,而且每个空间区域的相对位置,是比较确定的


5. 写实拷贝

当创建子进程的时候,将物理空间的内容再拷贝一份,然后在页表中父进程对应的虚拟地址映射到该物理空间,使得相同的虚拟地址映射不同物理空间

你可能感兴趣的:(Linux,操作系统,进程,缺页中断)