Linux程序地址空间

程序地址空间

地址:通常所说的的地址,都是内存的地址,是内存单元的编号。

在这里插入图片描述
但是我们所使用的硬件内存中,真的存在这些划分吗? 我们通过代码来探究一下。

#include <stdio.h>
#include <unistd.h>

int g_val = 100;  //创建一个全局变量 g_val
int main ()
{
	pid_t pid = fork();
	if (pid < 0)
	{
		return -1;  //创建子进程失败
	}
	else if (pid == 0{
		//创建子进程成功,子进程的返回值为0
		printf("child g_val=%d\n",g_val);
	}
	else
	{
		//父进程的返回值是子进程的PID,返回值大于0
		printf("parent g_val=%d\n",g_val);
	}
	return 0;
}

运行后我们可以发现父进程、子进程都可以打印出 g_val 的值。
在这里插入图片描述
我们将代码进行修改

#include <stdio.h>
#include <unistd.h>

int g_val = 100;  //创建一个全局变量 g_val
int main ()
{
	pid_t pid = fork();
	if (pid < 0)
	{
		return -1;  //创建子进程失败
	}
	else if (pid == 0{
		//创建子进程成功,子进程的返回值为0
		g_val = 200;
		printf("child g_val=%d\n",g_val);
	}
	else
	{
		//父进程的返回值是子进程的PID,返回值大于0
		sleep(3);
		printf("parent g_val=%d\n",g_val);
	}
	return 0;
}

在运行到子进程的时候,将全局变量 g_val 的值进行修改,然后父进程先进行休眠,等子进程将全局变量的值修改之后再进行输出,按理说,子进程和父进程的打印结果都应该是200,但是运行程序后我们发现
在这里插入图片描述
父进程打印的值是200,我们通过打印 g_val 的地址在来观察一下。

#include <stdio.h>
#include <unistd.h>

int g_val = 100;  //创建一个全局变量 g_val
int main ()
{
	pid_t pid = fork();
	if (pid < 0)
	{
		return -1;  //创建子进程失败
	}
	else if (pid == 0{
		//创建子进程成功,子进程的返回值为0
		g_val = 200;
		printf("child g_val=%d---%p\n",g_val,&g_val);
	}
	else
	{
		//父进程的返回值是子进程的PID,返回值大于0
		sleep(3);
		printf("parent g_val=%d---%p\n",g_val,&g_val);
	}
	return 0;
}

在这里插入图片描述

虚拟地址空间

通过观察地址我们发现,父子进程打印的 g_val 的地址也相同,难道值一个地址单元存放了两个数据吗?

当然不是,实际上,在进程中,程序访问的这些地址,都是假的地址,我们称之为虚拟地址空间,虚拟地址空间实际上是系统给进程所描述的的一个假的地址,在Linux下是一个 mm_struct 结构体。
系统会为每一个进程都分配一个假的地址空间,进程访问的都是虚拟地址,访问内存数据的时候,先将虚拟地址转换为物理地址之后,再进行访问。

为什么要用虚拟地址空间

系统会给每一个进程都描述一个完整的、连续的、线性的虚拟地址空间,实际物理内存是当需要的时候再进行分配,这样的话,对于每一个进程来说,都有一块儿自己的完整的、连续的内存可以使用。

在需要用到实际物理内存空间的时候,通过页表映射一块物理内存地址,这时,才是进行访问真正的物理内存。

通过这种映射的方式,实现了数据在物理内存上的离散存储方式,提高了内存利用率。

虚拟地址如何通过页表获取到物理地址

内存管理方式一共分为三种

  1. 分段式内存管理
  2. 分页式内存管理
  3. 段页式内存管理
分段式内存管理

将地址空间分成多段,便于编译器进行地址管理。

分段式虚拟地址组成:段号+段内地址偏移量。

在系统中,有一个段表,段表的内容包括段号,物理内存段起始地址。

图示:
在这里插入图片描述

分页式内存管理

将地址分成多个小块儿,实现数据离散式存储,提高内存利用率。

分页式虚拟地址组成:页号+页内偏移量。

在系统中,有一个页表,页表的内容包括页号,物理内存段起始地址,控制权限等。

图示:
在这里插入图片描述

段页式内存管理

将虚拟地址空间进行分段,在每个分段内进行分页式管理,集合了分段式和分页式的优点进行内存管理。

写实拷贝技术

通常,父子进程代码共享,父子进程在没有写入、修改等操作的时候,数据也是共享的,当任意一方试图写入的时候,通过写实拷贝技术拷贝一份副本,达到代码共享,数据独有的特性,这就是为什么父子进程的g_val为什么虚拟地址相同,但保存的数据不一样,就是子进程在修改g_val的值的时候,通过写实拷贝技术拷贝了一份副本,让相同的虚拟地址映射到不同的物理地址

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值