Linux学习:进程(4)程序地址空间(笔记)

1. Linux下各种资源的内存分布

在这里插入图片描述

2. 物理地址与虚拟(线性)地址

  1. 在有关进程创建的初步学习中,我们了解了fork函数创建子进程的方式。此种进程的创建方式使得同一个变量在不同的进程可以有不同的值,我们初步了解的原因,为子进程进行了写时拷贝,重新开辟了一块空间来存放值。
  2. 那么,既然是不同的地址空间,那么父子进程中的同名变量的地址一定是不同,可事实是这样我们,接下来我们进行相关验证。
int main()
{
     pid_t id = fork();
     int i = 0;
      
     if(id)
     {
         i = 10;
         while(1)
         {
             printf("this is father process i=%d,&i=%p\n", i, &i);                                                                                                                     
             sleep(2);
         }
     }
     else
     {
         i = 20;
         while(1)
         {
             printf("this is children process i=%d,&i=%p\n", i, &i);
             sleep(2);
         }
     }
 
     return 0;
}

在这里插入图片描述

  1. 运行结果如上,父子进程中的同名变量居然是同一块地址空间,一块地址空间是绝对无法存储两个数据的,可为什么这里却又显示它们的地址空间相同呢。
  2. 事实上,我们使用取地址操作得到的地址并非是真实的物理地址,而是虚拟的程序地址空间中的地址。
  3. Linux操作系统中,会在真实物理地址空间与每个程序之间生成一块虚拟的地址空间,每一个程序都有一块独属于自己的程序虚拟地址空间。我们取地址操作所获得的资源地址,只是其在这块虚拟地址空间上的地址,这些虚拟地址只是真正物理地址在这块空间上的映射。

在这里插入图片描述

3. 程序地址空间的区域划分

  1. Linux32位操作系统下,程序地址空间的大小都为4GB,与指针的物理地址空间大小相同。
  2. 程序地址空间也是一种数据结构对象,操作系统对计算机软硬件资源的管理方式都是信息管理,先描述对应事物的信息,然后再将其组织起来。
  3. 程序地址空间的信息属性:
    <1> 程序地址空间要做到的就是模拟一份与物理地址空间大小相同的虚拟空间。
    <2> 其次要能够对整块区域进行区域划分,来区分存储不同程序资源。
    <3> 在这一过程中,也要能够做到对越界资源的检测。
//大致的数据结构
struct area
{
	int code_start;
	int code_end;
	
	int init_start;
	int init_end;

	int uninit_start;
	int uninit_end;

	//.......
}
  1. 通过如上此种数据结构,对数据越界的检测也就编程了对数据区域的比对,而扩大与缩小区域,也就变成了结构内成员数据的增大与缩小。
  2. 程序地址空间不具有数据存储的能力,数据是存储在物理内存中的。

4. 地址映射与页表

  1. 前面我们已经提及,虚拟地址只是物理地址映射,可是映射方式具体是什么呢,在实现上是怎么做从而达成了这一目的的呢。
  2. 在虚拟地址与物理地址之间有一张记录它们映射关系的记录表,我们称之为页表。
  3. 在程序被执行的过程中,CPU获取对应进程真实地址空间的方式,为通过MMU硬件模块中的CR3寄存器中记录的页表地址,以虚拟地址空间为key值从而直接通过页表找到映射的真实物理地址。

在这里插入图片描述

  1. 虚拟地址空间与地址映射存在的意义:
    <1> 使得原本因进程众多,切换调度而无序的物理地址空间变成了有序的虚拟地址空间,让所有进程都可以以统一的视角看待内存,大大提高了进程运行的效率。
    <2> 使得物理地址存储数据的实现与虚拟地址程序运行的实现区分开来,互不干涉,达到了方便设计与解耦合的效果。
    <3> 进程地址空间 + 页表是保护内存的重要手段,当我们对内存进行非法操作(野指针,越界等)时,不会影响到物理内存与其他进程,操作系统只会崩溃当前进程。

5. 缺页中断

  1. 有了程序地址空间,我们再来了解一下动态空间管理的相关操作(malloc/new)。我们使用malloc/new申请款空间后,空间真的被开辟出来了吗?
  2. 当我们程序地址空间的堆区上申请了空间之后,物理空间上,我们所需的空间并不一定立刻会被开辟出来,在我们未对这段空间进行写入操作时,这段空间并不会被申请出来。只有在我们尝试进行写入时,操作系统才会为我们将这段空间真正开辟出来,并在页表中创建映射关系。
  3. 上述在对动态开辟空间进行写入的操作中,因为空间没有被指针开辟,页表上映射关系的缺失导致的操作短暂中断,我们称之为缺页中断。
  4. 操作系统为什么要进行这样写时拷贝的操作呢?操作系统是计算机资源的管理这,它为计算机的效率与资源使用率负责,如果在我们申请空间后,直接将进行开辟与权限开放,当我们只是申请而不使用的时候,就会浪费掉这块空间资源。操作系统为了杜绝防止这种资源浪费的风险,由此添加了写实拷贝的步骤。
  5. 写实拷贝的方式也能够提高我们内存申请的速度,虽然在总的时间上与申请开辟一体化的耗时相同,但单独对于申请的速度是有明显提升的。
  • 25
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值