目录 :
1.接上部分内容再谈谈地址空间是什么??
2.页表+MMU(硬件设备)
3.为什么要搞个虚拟地址映射到物理地址
4.解释为什么最开始的问题???
-------------------------------------------------------------------------------------------------------------------------
1.接上部分内容再谈谈地址空间是什么??
操作系统在创建进程的同时不仅仅创建PCB块,还必须创建这个进程对应的进程地址空间
所以操作系统既然要对进程管理,当然也对进程的地址空间进行管理
操作系统对进程的管理是通过对应的数据结构进行管理
那么操作系统对地址空间的管理也是通过一种数据类型 (进程地址空间本质是内核中一种数据类型)
struct mm_struct{
//进程地址空间
}
对进程地址空间作进一步理解(引出虚拟地址的概念)
小时候你的同桌是一位爱干净的女孩子,然而你是一位非常不爱干净的男孩子,老是流口水什么的,所以你的同桌小女孩非常的反感你,决定和你划分界限
所以我们的mm_struct 本质就是一个一个的区域
struct mm_struct
{
unsigned int code_start
unsigned int code_end;
unsigned int init_data_star;
unsigned int init_data_end;
……
}
虽然这里只有star 和 end 但是每个进程都可以认为mm_struct 代表整个内存,且所有的地址为
0x00000000 - 0xFFFFFFFFFF
2.页表+MMU
这就要引出页表和MMU(硬件设备)
页表的核心工作就是将虚拟地址转换成物理地址
3.为什么要搞个虚拟地址映射到物理地址
为什么要这么干???????
所以我们在进程和物理内存当中添加了一个角色 --》 操作系统
而进程地址空间和页表就是操作系统的对应的一个真正管理者角色
虚拟地址转换成物理地址,是通过页表和MMU,那么是谁帮助页表在转换呢???
当然是操作系统了,操作系统帮助页表和MMU去转化。
常量字符串不可被修改的根本原因
1.通过添加一层软件层,完成有效的对进程操作内存进行风险管理,本质是为了保护物理内存以及各个进程的数据安全
我们申请了1000个字节,我们立马能使用1000个字节嘛?????
不一定,可能会存在暂时不会全部使用,甚至暂时不用!!!
那肯定不能闲置着阿,我们来看看操作系统是怎么处理的
所以操作系统拿着这在进程地址空间开辟的虚拟地址空间返回给了进程
过了一段时间进程要使用刚刚在堆区上开辟的100字节空间了,但是这时候这块100字节空间还没有在物理内存上开辟,操作系统说等等
操作系统这时候在去物理内存上给你申请一部分空间,接下来把你在进程地址上的虚拟地址和物理内存上的地址在页表建立映射关系。
完成之后,在让进程去对刚刚开辟的100字节空间进行内存操作
当你真正需要用的时候,操作系统在去物理内存上开辟(这种叫做基于缺页中断进行物理内存申请)
2.将内存申请和内存使用的概念在时间划分清楚,通过虚拟地址空间,来屏蔽地层申请内存的过程,达到进程读写内存和OS进行内存管理操作,进行软件上面的分离
我们先来思考一个问题 CPU是怎么知道你的第一行代码在哪里呢???
如果没有地址空间那么CPU读取我们内存的时候
这样子的话CPU就生气了,一气之下决定每次都只从0x1234的地址出读取代码
那么有了页表,CPU就方便了
CPU将程序的代码和数据加载到物理内存当中,将物理内存的地址保存在这个进程对应的页表物理地址当中,而CPU设定了只从0x1234开始读,那么我们将虚拟地址0x1234和我们的刚刚保存的将代码和数据加载到内存当中的物理地址进行映射
每一个进程的正文代码的虚拟地址相同,只需要我们页表的映射不同,CPU不就可以通过页表的映射快速的找到每一个进程的在物理内存当中的数据和代码了嘛
3.站在CPU和应用层的角度,进程统一可以看作统一使用4GB空间,而且每个空间区域的相对位置是确定的!!!
并且我们进程的数据和代码可以加载到物理内存的任意位置(只需要我们的页表和我们的虚拟地址形成映射即可)
OS最终这样设计的目的,只为了达到一个目标 :每个进程都认为自己是独占系统资源的
4.解释为什么最开始的问题???
只要父子进程都不对数据进行修改,那么父子进程对数据都是用同一份的,当父子进程要对数据进行修改时,那么就会发生写实拷贝
父子进程一般的代码是共享的
所以,所有的只读数据,一般可以只有一份