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

news/2024/10/6 20:49:01 标签: linux, 服务器, 运维

目录

现象

底层原因

数据不发生修改

数据修改

小总结

地址空间本质

为什么要有地址空间


现象

 来看代码:

#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的本质就是写入(修改),发生写时拷贝!

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

地址空间本质

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

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

为什么要有地址空间

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

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

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

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

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

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

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


http://www.niftyadmin.cn/n/5692152.html

相关文章

HTML ASCII:Web 开发中的字符编码基础

HTML ASCII&#xff1a;Web 开发中的字符编码基础 ASCII&#xff0c;全称为美国信息交换标准代码&#xff08;American Standard Code for Information Interchange&#xff09;&#xff0c;是一种用于电子通信的字符编码标准。它最初于1963年提出&#xff0c;用于在不同的计算…

面试系列-分组Tire树匹配算法

自己写的分组Tire树匹配算法&#xff0c;该算法用于云南省人工智能重点实验室与云南电网合作项目&#xff08;云南电网敏感信息识别系统&#xff09;&#xff0c;用于快速匹配文本将项目中数据算法抽离出来&#xff0c;特此分享&#xff01;&#xff01;!可以实现动态的插入、删…

华为OD机试 - 约瑟夫问题(Python/JS/C/C++ 2024 E卷 200分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

Vue3 动态路由实现的一种方法

动态路由 目的&#xff1a; 根据服务器传回来的数据动态的注册路由信息&#xff0c;登录用户的角色不同生成的菜单不同 使用插件做动态路由的好处&#xff1a; 路由页面增加或者减少时&#xff0c;只需要增加或减少相关的路由文件&#xff0c;不需要再修改代码 服务器返回的信…

《计算机原理与系统结构》学习系列——计算机的算数运算(上)

系列文章目录 目录 ALU行波进位加法器超前进位加法器整数运算加减法乘法无符号数相乘N位乘法数的工作流程N位乘法器改进&#xff1a;硬件资源更快速的乘法 MIPS中的乘法除法 32位除法器流程除法器改进 更快速的除法 MIPS中的除法总结 ALU ALU功能&#xff1a;对a&#xff0c;…

Pikachu-SSRF(curl / file_get_content)

SSRF SSRF是Server-side Request Forge的缩写&#xff0c;中文翻译为服务端请求伪造。产生的原因是由于服务端提供了从其他服务器应用获取数据的功能且没有对地址和协议等做过滤和限制。常见的一个场景就是&#xff0c;通过用户输入的URL来获取图片。这个功能如果被恶意使用&am…

【STM32】TCP/IP通信协议(2)--LwIP内存管理

五、LWIP内存管理 1.什么是内存管理&#xff1f; &#xff08;1&#xff09;内存管理&#xff0c;是指软件运行时对计算机内存资源的分配的使用的技术&#xff0c;其主要目的是如何高效、快速的分配&#xff0c;并且在适当的时候释放和回收内存资源&#xff08;就比如C语言当…

【鼠鼠学AI代码合集#7】概率

机器学习与概率——理解预测的核心 1. 机器学习的本质&#xff1a;基于数据做预测 机器学习的核心目标是基于已有的数据来进行预测和推断。在不同领域&#xff0c;机器学习的应用场景广泛&#xff0c;但背后的逻辑都是基于概率模型来估计某种事件发生的可能性。以下是几个典型…