【Linux】进程第三弹(虚拟地址空间)

目录

现象

底层原因

数据不发生修改

数据修改

小总结

地址空间本质

为什么要有地址空间


现象

来看代码:

cpp 复制代码
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int val = 50;

int main()
{
	printf("father process is running,pid is:%d,ppid is:%d,val:%d,&val:%p\n", getpid(), getppid(), val, &val);
	pid_t id = fork();
	if (id == 0)
	{
		int cnt = 0;
		while (1)
		{
			printf("child process,val:%d,&val:%p\n", val, &val);
			cnt++;
			sleep(1);

			if (cnt == 3)
			{
				val = 100;
				printf("child proess change 50->100\n");
				printf("child process,val:%d,&val:%p\n", val, &val);
				sleep(1);
			}
		}
	}

	else if (id > 0)
	{
		while (1)
		{
			printf("father process,val:%d,&val:%p\n", val, &val);
			sleep(1);
		}
	}


	return 0;
}

如上述代码,定义一个全局变量val,分别在父子进程中打印内容和地址,当在子进程运行3s后,更改其值。来看看结果。

从上图不难看出,没修改前父子进程的val都是50,地址也一样;当在子进程修改后,子进程打印出来了100,而父进程还是50,但是地址还是一样的!!很奇怪!!?

  • 同一变量名输出不同的内容,说明父子进程中用的并不是同一个变量。
  • 每一个变量都会有属于自己的物理空间(地址)。。说明,使用程序代码打印出来的这个地址绝对不是物理地址!
  • 实际上,在Linux中,对于这样的地址就被称为虚拟地址!平时我们采用C/C++打印出来的地址,都是虚拟地址,并不是数据真正在内存中的地址!
  • OS在创建进程时,不仅仅将进程的代码和数据加载到内存,还会为每一个进程创建一个地址空间,这个地址空间就是虚拟地址空间!!

既然是虚拟地址,那又怎么找到当前数据所在内存的位置?只有知道位置,才能进行数据的访问和修改。因为内存和代码被加载到了物理内存中。。

实际上OS也会为每个进程建立一个页表,这个页表能够将虚拟地址和物理地址建立起映射的关系!操作系统会自动将虚拟地址转化为物理地址。。

底层原因

数据不发生修改

  • 这种情况父子进程的页表映射的是同一个地址。因为子进程会继承父进程内容,父进程的代码和数据子进程都能看到(不能修改)

数据修改

  • 这种情况会发生OS发生写时拷贝。OS会在内存重新找一块空间,将数据拷贝下来再做修改,并重新更新子进程的页表,重新建立新的映射关系。

为什么要发生写时拷贝?

  • 因为进程具有独立性,多进程运行,都需要独享各种资源,进程之间不能相互干扰。
    能不能在创建子进程的时候就将父进程的数据全部写时拷贝呢?

  • 可以,但是没必要,因为子进程不一定会全部修改父进程的数据,写时拷贝是有一定的消耗的,应该要按需分配,修改的时候在写时拷贝,这样更能节省消耗!

小总结

①上述程序运行的结果足矣说明,同一个变量,地址相同,本质是虚拟地址相同,内容不同本质是被映射到的物理地址不同!

②这也解释了fork函数,同一个id变量名为什么既能>0,又能小于0的原因。因为fork函数会返回两次,即return,return的本质就是写入(修改),发生写时拷贝!

cpp 复制代码
//fork会return,对父进程的id写入,发生写时拷贝!
pid_t id=fork();
if(id==0)
{
    //child
    ....
}
else if(id>0)
{    
    //father
    .....
}

地址空间本质

进程地址空间,在内存中是一种内核数据结构,在Linux中本质就是一个mm_struct的结构体,这个结构体内部的属性都是表示某一个区域的范围。。

就好像一把直尺,每一部分的内容都有属于自己的范围!

为什么要有地址空间

①拦截非法请求,变相保护物理内存!

  • 如果没有地址空间,进程直接访问物理内存,极大的增加系统异常的概率。
  • 加上地址空间,进程首先得先通过地址空间这一关,比如访问数组越界等异常问题,地址空间会立马报错,阻止进程继续访问物理内存!

②进程管理模块和内存模块的解耦,实际是提高内存利用率。

  • 如果在创建进程的时候,直接申请物理内存。若进程长时间不使用物理内存,那必然会造成资源的浪费
  • 有了虚拟地址空间,可以在页表先申请出虚拟地址,当进程实际需要使用内存,再申请内存空间,并建立映射关系,极大提高内存利用率。

③将无序变有序,让进程以统一的视角看待物理内存以及自己运行的各个区域。

  • 有了地址空间,每个进程都无需关心具体的数据在物理内存中的位置,只需知道虚拟地址,OS会通过页表映射到对应的物理位置!

好了,今天的内容就分享到这里,如果你有所收获,欢迎三连,xd!

相关推荐
粤海科技君8 分钟前
如何使用腾讯云GPU云服务器自建一个简单的类似ChatGPT、Kimi的会话机器人
服务器·chatgpt·机器人·腾讯云
傲骄鹿先生18 分钟前
阿里云centos7.9服务器磁盘挂载,切换服务路径
服务器·阿里云·磁盘
有谁看见我的剑了?1 小时前
Ubuntu 22.04.5 配置vlan子接口和网桥
服务器·网络·ubuntu
铁锤妹妹头发多1 小时前
新手用docker真**难受
运维·docker·容器
2739920291 小时前
Ubuntu20.04 安装build-essential问题
linux
超栈1 小时前
HCIP(11)-期中综合实验(BGP、Peer、OSPF、VLAN、IP、Route-Policy)
运维·网络·网络协议·计算机网络·web安全·网络安全·信息与通信
Cachel wood1 小时前
Github配置ssh key原理及操作步骤
运维·开发语言·数据库·windows·postgresql·ssh·github
编程一生1 小时前
回调数据丢了?
运维·服务器·前端
华为云PaaS服务小智1 小时前
华为大咖说 | 浅谈智能运维技术
运维·华为·华为云
zhd15306915625ff3 小时前
化工厂主要涉及的自动化备件有哪些?
运维·自动化·化工厂