Linux:进程虚拟地址

进程虚拟地址空间:程序地址空间应称为 → 进程虚拟地址空间
为什么这么说,我们先来看一段代码
在这里插入图片描述

变量被static修饰后,编译器会把该变量编译到全局区
就变成了全局变量,作用域在被定义的函数内,生命周期跟随程序
栈向低地址生长
堆向高地址生长

在这里插入图片描述

  • 父进程有一个全局变量val=0,创建子进程,
  • 在子进程中对该val的值进行修改,并分别打印val分别在父子进程中的值和地址

输出结果:

父进程val值为0 ,地址0x11223344
子进程val值为100,地址0x11223344

现象:父进程创建子进程,并都去打印全局变量产生的问题:

  • 子进程创建成功后拷贝父进程的PCB,
    它们各自的内存指针,指向各自的进程虚拟地址空间,其中的代码段和父进程的一样;

现象:父子进程是两个不同的进程,打印出全局变量的地址一模一样;

  • 按照对内存的理解,不同进程使用内存应在不同的物理内存上,&符号拿到地址应该不同;
  • 在C/C++代码中用&符号获得的地址,都是操作系统虚拟出来的地址,并不是真正的内存条中的物理地址

离散分配:提高对内存的使用率

进程地址空间

内存是一个硬件,不能阻拦程序员访问,只能被动接收读取和写入
代码的只读特性是如何做到的呢

  • C、C++中的地址都不是物理地址,都是虚拟地址
  • 每一个程序在启动时,操作系统会为其虚拟一段4G的地址空间
    每一个进程都认为自己独占系统中所有的资源
  • 虚拟地址空间中的每个区域,都要经过 页表 映射到物理空间
    页表结构将虚拟地址和物理地址对应起来,每个进程都有一个页表结构
  • mm_struct
    进程地址空间是task_struct中的一个数据结构—struct mm_struct
    mm_stuct中有一个结构体,里面通过指针保存每一段区域的起始和结束地址,以及该区域的权限

程序如何变成内存

程序被编译出来后,没有被加载的时候,程序内部是有地址的
链接的时候,需要把库中的函数地址,填入调用的调用函数的地方

程序被编译出来后,没有被加载的时候,程序内部是有区域的(这里采用相对地址/逻辑地址)

程序加载到内存前后,两者地址的区别
在加载前,每个区域是采用相对地址划分的,类似结构体对齐的地址,起始地址为0
加载后,在内存开辟一段空间,这段内存空间有起始地址
最后程序在内存中,各个区域的地址都会加上 加载后的起始地址

页表结构

在这里插入图片描述

虚拟地址转化成物理地址三种方式:

1. 分页式:

通过虚拟地址算出页号,通过页表找到相应块号,通过块号找到相应块的起始位置,再加上页内偏移找到具体物理地址(图同分段式,只是名字不一样)

虚拟地址 = 页号 + 页内偏移

  • 一个0x11223344这个虚拟地址是由两部分构成,一个是页号,一个是页内偏移;也就是说操作系统知道每一个通过虚拟地址得到对应的物理地址
    在这里插入图片描述

操作系统在进行管理时,

  • 将进程虚拟地址空间分成一页一页的小块;
  • 每个小块的大小通常为4kb (4096个字节),每块大小在512字节~8kb之间;
  • 并且将物理内存分成了和一页大小相同的物理块(左边叫页,右边叫块)
  • 页表:第一列保存的是页号,第二列保存的是块号
  • 页表结构:将虚拟地址与物理地址对应起来;页表结构有两列

虚拟地址转化成物理地址:

  1. 通过一个虚拟地址一定可以知道该地址对应的页号,在页表中查到对应的页号找到块号,通过块号找到物理内存;
  2. 一块物理内存有4096个字节,也就是说有4096个地址;所以找到块号也不能确定虚拟地址对应的物理地址,还要再加上偏移量
  3. 通过虚拟地址计算页号和页内偏移:
    页号 = 虚拟地址 / 页的大小
    页内偏移 = 虚拟地址 % 页的大小

2. 分段式:

通过虚拟地址得到段号,通过段号找到段的起始地址,段的起始地址+段内偏移得到物理地址
在这里插入图片描述

虚拟地址 = 段号 + 段内偏移
段表:也是两列 段号 + 段的起始地址

在这里插入图片描述

3. 段页式:

通过段号找到页表起始位置(也就是找到了哪个页表),通过页号对应块号,通过块号找到物理内存中某个块的起始位置,通过页内偏移在块中找到物理地址

虚拟地址=段号+页号+页内偏移

在这里插入图片描述

在操作系统中存在一个段表若干个页表
段表第一列是段号;第二列是页表的起始位置
页表第一列是页号;第二列是块号

其它概念:

  1. 进程间的运行是抢占式执行
  2. 并行和并发
    并行:多个进程同时拥有不同的CPU进行运算----有多个CPU
    并发:多个进程在同一时刻只能有一个进程有CPU进行运算----单个CPU
  3. 独立性:一个进程被创建,该进程就是独立的,其它进程不会影响到该进程
    复杂指令集:直接写一条指令
    精简指令集:拆分很多模块,写成很多指令,运行一条新指令时会找一下之前是否有相同模块的指令
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值