Linux下进程虚拟地址空间详解

一,程序地址空间

计算机物理内存的大小是固定的,就是计算机主板内存槽上的实际物理内存,cpu可以直接进行寻址,物理内存的容量是固定的,但是寻址的空间取决于cpu地址线的数量。在32位系统上,线性地址空间可达4G(2^32);这4G一般是按照3:1的比例进行分配,用户进程享有3G的空间,而内核独自享有剩下的1G内存。
在这里插入图片描述

早期的内存分派方式:
在这里插入图片描述

最早的时候,计算机还没有虚拟机制,程序指令所访问的内存地址就是物理内存地址,所以就要将所有程序都加载到内存中,但是我们实际的物理内存只有4G。所以就会出现一些问题:

  • 当多个程序需要运行时,必须保证这些程序用到的内存总量要小于计算机实际的物理内存的大小
  • 内存使用效率低,内存空间不足,就需要将其他程序展示拷贝到硬盘当中,然后将新的程序装入内存。然而由于大量的数据装入装出,内存的使用效率会非常低。
  • 进程地址空间不隔离,由于程序是直接访问物理内存的,所以每一个进程都可以修改其他进程的内存数据,设置修改内核地址空间中的数据,所以有些恶意程序可以随意修改别的进程,就会造成一些破坏。
  • 程序运行的地址不确定;因为内存地址是随机分配的,所以程序运行的地址也是确定的

二,进程虚拟地址空间

虚拟地址的引入:

虚拟地址是程序运行时,程序访问存储器所使用的逻辑地址称为虚拟地址,通过逻辑地址映射到真正的物理内存上。

1.进程虚拟地址空间,也就是意味着认为规定的逻辑地址空间。
2.每个进程都可拥有3G的虚拟地址空间,并且用户进程之间的地址是互不可见,互不影响的,也就是说,即使俩个进程对同一块地址进行操作,也不会产生问题。
3.虚拟地址是不具备存储能力的,数据的存储依然要存放在物理内存中。
4.可以通过页表映射从逻辑地址空间访问真实的物理地址空间。

在这里插入图片描述

三,写时拷贝

写时拷贝:当父进程定义了一个全局变量,fork出来一个子进程,当子进程发生对该全局变量发生修改的时候,操作系统会重新开辟一段空间来保存子进程更改后的值,则子进程会更改自己的页表映射关系
如果说父子进程都不改变原来的内存当中的值,页表的映射关系还是映射到同一块物理内存当中。

代码演示:

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

int aa = 10;
int main()
{
	pid_t pid = fork();
	if (pid<0) //进程创建失败
		perror("error");
	else if (pid == 0)// child 
	{	
		aa += 10;
		printf("child:&aa=%p aa=%d\n", &aa, aa);
	}
	else // father
	{		
		aa -= 10;
		printf("father:&aa=%p aa=%d\n", &aa, aa);
	}
	return 0;
}

运行结果:

[vitobo@iZ2zeam1x9vamvgeqa97adZ test]$ ./test
father:&aa=0x601044 aa=0
child:&aa=0x601044 aa=20

分析:

1.当创建一个子进程的时候,子进程会拷贝父进程的页表结构,也就是说会将父进程虚拟地址空间和物理内存之间的映射关系也拷贝了。
2.如果创建完成子进程,子进程也会通过页表结构映射到物理内存的同一块区域。
3.如果父子进程都不进行修改,则映射的关系不会修改。
在这里插入图片描述

四,存储管理方式–分页式

页表:页表的作用是虚拟地址映射成物理地址的。
在这里插入图片描述

分页式:

页号:进程会将虚拟地址空间分成一页一页的结构。
前提:会将虚拟地址空间分成一页一页的格式,会将物理内存分为一块一块的格式。一页大小=一块大小=4096k
页表当中维护的就是页和块的关系。
页号+页内偏移: 通过页号找到块号;通过块号,算出块的起始地址,最后块的起始地址加上业内偏移
在这里插入图片描述

计算:假设虚拟地址为5000,块的大小是4096,请你计算物理地址

页号 = 虚拟地址/块大小
页号:5000/4096=1
页内偏移 = 虚拟地址%块的大小
页内偏移:5000%4096=904

块号:根据页号在页表当中的映射去查找块号
如上图当前页号为1,找到了块号为5
块的起始地址 = 块号*块大小
块的起始地址:54096
物理地址 = 块的起始地址+页内偏移
物理地址:5
4096+904=21384

分页式内存管理的优点:实现数据离散式存储,提高内存利用率,并且通过页表进行内存访问控制

五,存储管理方式–分段式

分段式:将虚拟地址的组成分为段号+段内偏移
通过段号找到段的起始地址;然后段的起始地址加上段内偏移。
物理地址=段的起始地址+段内偏移
在这里插入图片描述

分段式内存管理的优点:对编译器的地址管理比较友好的; 但是没有解决数据连续存储利用率低的问题。因为一个段管理了很多变量数据,这些变量就都是通过同一个起始地址进行偏移的,也就是在物理地址中使用了连续的地址空间(分页式管理中,同一个段内地址数据都使用了连续的地址空间)

六,存储管理方式–段页式

段页式:段号+页号+页内偏移
1.通过段号找到页的起始地址
2.通过页的起始地址,找到对应的页表结构
3.通过页号,在页表当中找到对应的块号
4.通过块号乘以块大小找到块的起始地址
5.块的起始地址加上页内偏移,找到具体的物理地址。 在这里插入图片描述

七,进程优先级

1.进程优先级是为了保证操作系统调度进程的时候,比较合理。
2.进程优先级可以使用命令去查看
top命令查看
在这里插入图片描述
PR 进程优先级的数值 不能直接去修改PR这个值
NI 进程优先级的修正值 可以修改NI值来修改PR值
新的PR值= 旧的PR值+NI
3.修改NI值
top -->r -->输入进程的pid -->输入修改后的NI值
4.nice其取值范围是-20至19,一共40个优先级
5.进程优先级的数值越小代表优先级越高
6.虽然用户可以改变NI值,从而来改变PR值,但是操作系统调度的解释权归操作系统所有

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值