进程地址空间的理解

目录

进程地址空间的排布

静态分布

动态开辟

static修饰的变量

进程地址空间

为何说进程地址是虚拟的?

如何划分区域?

通过页表和物理内存建立联系

虚拟地址如何形成?

分析为何一个地址两个不同变量?

为什么要有虚拟地址?


进程地址空间的排布

操作系统中的地址排布如下:

静态分布

用代码来查看内存的静态分布:

动态开辟

堆开辟空间是由下到上开辟

栈开辟空间是由上到下开辟

代码验证:

static修饰的变量

被static修饰的变量,作用域不变,生命周期改变--相当于一个全局变量的生命周期, 是一个定义在函数中的全局变量:

进程地址空间

进程地址空间是什么,和之前的地址空间有什么不同吗?

以前定义变量、代码调试等操作,以为自己在监视窗口中看到的空间就是物理空间,其实是不准确的;我们以前认为的,其实不是物理地址,而是虚拟地址--进程地址空间。

为何说进程地址是虚拟的?

因为它可以实现同一个地址,存储的值不同!!!如下:

 当父子其中一个进程中修改了全局变量的值后:

如果我们这里获取到的是物理地址空间,那么是不可能存在一个相同的地址存储了不同的值

进程是具有独立性的,当全局变量未修改时,父子进程共享同一段物理内存;

修改后,虚拟地址相同,但是获取到的值不同,那么一定是有两份物理内存来分别存储不同值,只是虚拟地址相同罢了。

如何划分区域?

在 mm_struct 这个结构体中,还存有一些结构体的指针,这些结构体中定义了每个区域的开始 start 和结束 end;由此堆进程地址空间进行了区域划分。

通过页表和物理内存建立联系

虚拟地址如何形成?

在程序在磁盘上要加载到内存形成进程,文件编译时(按照0000~FFFF进行编址),就会在磁盘中生成逻辑地址(相对地址),加载到内存中时,会以统一的标准:对逻辑地址进行一定的偏移,生成虚拟地址

不同区域的虚拟地址连起来组成了进程地址空间,进程的 task_struct 中 mm_struct 指向它。

由此我们可以知道程序编译后,没有加载到内存时,就已经有地址和区域了,加载只是将所有地址进行了二次加工变成虚拟地址而已。

分析为何一个地址两个不同变量?

进程具有独立性,代码共享数据独立。那么数据是如何独立?子进程会继承父进程 task_struct 大部分数据,包括 mm_struct 以及页表

当在子进程下数据发生改变后,页表左侧的虚拟地址不改变,但与之对应的右侧物理地址发生改变,系统为确保数据的独立,分配新的物理内存给子进程

因此我们得到的地址是没有改变的虚拟地址,因为进程的独立性,页表也独立,虚拟地址不变,但是各自的页表上虚拟地址对应的物理地址不同。

上图所示的这中情况叫做写时拷贝,当进程需要内存空间时,先改变 mm_struct 中控制对应区域的大小--提前调节所需要的内存,相当于先声明在哪个区域,需要多少。等到需要写入数据时,才会根据区域为其开辟对应内存。

为什么要有虚拟地址?

1. 因为硬件只会被动的读取和写入,可以对转化过程进行审核,拦截非法操作,保护内存;

2. 通过地址空间,进行功能模块的解耦,令申请空间与访问空间分离;申请空间声明我要多少,访问空间时进行分配,写时拷贝,提高空间利用率;

3. 让进程或者程序用统一的视角看待内存,都在编译时转换为虚拟地址,需要访问时只管分配内存即可,简化进程本身的设计和实现。

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

今年依旧去年春

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

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

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

打赏作者

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

抵扣说明:

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

余额充值