Linux进程地址空间与块注释

🍊程序地址空间

进程地址空间图

image-20220116222258292

checkarea.c

#include<stdio.h>    
#include<unistd.h>    
#include<stdlib.h>    
    
int glo_val=0;    
int uninit_val;    
    
int main(int argc,char* argv[],char* env[])    
{    
  //代码区    
  printf("code addr:%p\n\n",main);    
  //字符常量区    
  const char* p="hello world!";    
  printf("read only addr:%p\n\n",p);    
  //已初始化全局变量区    
  printf("glo_val addr:%p\n",&glo_val);    
  //未初始化全局变量区    
  printf("uninit addr:%p\n\n",&uninit_val);    
  //堆区    
  char* q=(char*)malloc(10);    
  printf("heap addr:%p\n\n",q);    
  //栈区    
  printf("stack addr:%p\n",&p);    
  printf("stack addr:%p\n\n",&q);    
  //命令行参数    
  printf("args addr:%p\n",argv[0]);    
  printf("args addr:%p\n\n",argv[argc-1]);    
  //环境变量    
  printf("env addr:%p\n\n",env[0]);    
    
  //测试static修饰的变量在哪块区域    
  static int a=0;    
  printf("static addr:%p\n\n",&a);                                                                                                                        
    return 0;
}    

运行:image-20220116222454360

将其与代码一一对应起来:

image-20220116223649233

🍈虚拟地址

#include<stdio.h>    
#include<unistd.h>      
   
int glo_val=0;    
 
int main()    
{    
  int ret=fork();    
  if(ret>0)    
  {    
  	//parent    
    while(1)    
    {    
      sleep(1);    
      printf("\n i am father::glo_val:%d, &glo_val:%p\n",glo_val,&glo_val);   
    }    
  }    
  else    
  {    
    //child    
    glo_val=100;    
    while(1)    
    {    
      sleep(1);                                                      
      printf("\n i am son::   glo_val:%d, &glo_val:%p\n",glo_val,&glo_val);   
    }    
  }    
  return 0;    
}

运行:

image-20220116224857353

观察运行结果,为什么两个的地址一样,但是值却不同???

想直接知道结果,就可以直接拉到最后了

到这里引出虚拟内存,显然同一块空间不可能有两个值,因为我们从学C语言起(没学系统前)取到的地址都是虚拟地址,而不是真正的物理地址,我们在语言层面拿到的都是虚拟地址。

image-20220116230350224

  • 虚拟内存本质上也不过是结构体(mm_struct)(源码没找到,建议Linux源码版本别下太高了,不好找😥),在mm_struct里规定了地址的起始,比如0x00000000到0x11111111这块代表代码区

  • 假如内存是4G,每个进程都会以为自己拥有了4G的内存(虚拟)

    讲个小故事帮助理解,一个身价十亿的富豪,有十个私生子,他对每个私生子说:百年之后我把自己的所有财产都归到你名下,私生子之间并不知道对方的存在,所以每个私生子都会以为自己拥有十亿,私生子每次向自己的父亲要钱父亲都会给予回应

    再比如你把十万存入银行,你以为自己有的十万,你每次要一两万都能到从中取出来,你以为你拥有十万,但是你每次取得并不是原先的十万。

    正如进程需要内存空间,他是觉得自己拥有全部内存的。

  • 页表就相当于一种映射关系

  • 虚拟地址是靠操作系统提供的,虚拟内存与物理内存的转化靠的是操作系统

  • 进程地址空间不是内存,而是随着进程一直存在(因为本身就只是C语言模拟出来的程序而已)

🍈四个问题

🥝进程地址空间究竟是什么?

  • 进程地址空间本质上是进程看待内存的方式,在Linux源码里虚拟内存与两个结构体的实现密切相关(其中一个就是mm_struct),地址空间也是被抽象出来的一个概念

  • 区域划分的本质(堆栈 代码区之类的划分)本质上是将线性的地址空间划分为一块一块的,或者说给线性的地址空间加上边界(举个例子,假设代码区[0x00000000,0x11111111])

  • 虚拟地址的本质:在这个区域之间的地址就叫虚拟地址

  • 进程地址空间在进程的生命周期内一直存在

🥝为什么要存在虚拟地址空间?

  • 保护物理内存

    没有虚拟内存,直接操作物理内存的话,来一个恶意程序那物理内存容易受到打击

  • 让内存管理和进程管理解耦(没有那么紧密相关)

    操作系统的主要功能:

    进程管理

    内存管理

    文件管理

    设备管理

    理解管理可以看看专栏前面的笔记

  • 让每个进程都可以以一样的方式来看待代码和数据(确定了一种方式)

🥝进程地址空间的分布?

image-20220117001027246

🥝地址空间和物理内存之间的关系?(浅谈)

虚拟地址和物理地址之间通过页表完成映射关系

我还没学完,所以只有一点,以后还会提到这个问题

🍈地址相同内容不同问题详解

图片版:
image-20220117004815000

简而言之:虚拟地址一样,不代表在物理内存的地址一样

文字版:fork()函数创建了子进程,子进程的PCB(task_struct)里的信息大多数与父进程一样,而glo_val=100后改变了数据,数据改变后就得拷贝一份新的数据(写时拷贝),新的数据自然有新的地址,也即子进程通过页表映射的地址改变了,所以访问新的数据自然是100,而虚拟地址一样,只是看起来一样而已,并不能代表物理内存是同一块

🍈进程与程序的区别?

  • 进程是动态的,程序是静态的

  • 进程具有并发性,程序没有

  • 进程是暂时的(运行完就没了),程序一直在

  • 进程会竞争CPU资源,程序不会

  • 进程与程序的组成不同,进程包括程序、数据和PCB(进程控制块)

随笔记录:页表有帮助系统进行合法性检测的作用(比如地址越界)

语言层面是看到的都叫虚拟地址

指针越界可能影响进程独立性

虚拟地址的线性功能利于寻址

可执行程序本身就被划分为一个一个的区域,利于链接之类的操作

🍈小技巧:块注释(hjkl)

vim打开文件 -> ctrl+v进入visual block模式 -> 用hjkl来操作光标(不能用上下左右方向键)-> 选中注释行 -> 输入大写的i (I) 进入插入模式 -> 输入//(在插入模式下) -> 按下ESC

就可以发现选中行都注释了

演示过程:

markdown博客演示28

  • 17
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喜欢乙醇的四氯化碳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值