Linux进程虚拟地址

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

在这里插入图片描述

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

输出结果:

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

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

  • 子进程创建成功后拷贝父进程的PCB,它们各自的内存指针,指向各自的进程虚拟地址空间,其中的代码段和父进程的一样;
  • 父子进程是两个不同的进程,打印出全局变量的地址一模一样;
  • 按照对内存的理解,不同进程使用内存应在不同的物理内存上,&符号拿到地址应该不同;
  • 在C/C++代码中用&符号获得的地址,都是操作系统虚拟出来的地址,并不是真正的内存条中的物理地址

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

对虚拟地址的理解,以及操作系统如何联系虚拟地址和物理地址

虚拟地址的产生是为了操作系统方便统一管理物理内存

  • 每一个程序在启动时,操作系统会为其虚拟一段4G的地址空间,这上面的每一个地址不是真是的物理地址,只是一个编码不能保存实际数据;
  • 操作系统只需要维护进程与物理内存的一个映射关系,用到了一个叫做页表结构的维护;
  • 页表结构将虚拟地址和物理地址对应起来,对于每个进程都有一个页表结构;
    要操作数据需要通过虚拟地址找到页表的映射关系,再找到具体的物理内存
  • 虽然为每个进程分配4G虚拟空间,如果进程只用20M,在这个页表关系中也只映射20M空间
  • 所以在代码中打印出来的地址并不是物理地址而是虚拟地址

页表结构:
在这里插入图片描述

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

1. 分页式:

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

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

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

操作系统在进行管理时,

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

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

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

2. 分段式:

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

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

在这里插入图片描述

3. 段页式:

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

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

在这里插入图片描述

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

其它概念:

  1. 进程间的运行是抢占式执行
  2. 并行和并发
    并行:多个进程同时拥有不同的CPU进行运算----有多个CPU
    并发:多个进程在同一时刻只能有一个进程有CPU进行运算----单个CPU
  3. 独立性:一个进程被创建,该进程就是独立的,其它进程不会影响到该进程
    复杂指令集:直接写一条指令
    精简指令集:拆分很多模块,写成很多指令,运行一条新指令时会找一下之前是否有相同模块的指令

版权声明:本文为qq_45481606原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。