一.程序地址空间(其实就是虚拟地址空间)回顾

我们在以前学习C/C++时,见过这样的布局图,可是我们对它并不理解!
本节我们将对它有一个全面的理解
二.虚拟地址
问题1.什么是虚拟地址?
问题2.什么是虚拟地址空间?
问题3.虚拟地址与物理内存地址有什么关系?
问题1:
下面的代码中val的地址其实就是虚拟地址
问题2:
虚拟地址空间中存储的地址就是虚拟地址
问题3:
虚拟地址空间和物理内存之间有一套页表,数据和代码对应的虚拟地址和物理内存地址一一映射在页表,虚拟地址通过页表的映射关系找到物理内存地址

原因:我们可以看到实验的现象:父进程和子进程的val值不同,但是地址却是一样的,难道是我们以前所学内容出错了吗,一个地址难道可以存储多个内容吗?显然不能,我们所学的内容也并没有出错,而是因为我们在这里所取到的地址不是实际的物理地址,而是一个虚拟地址!,数据存储在物理内存地址上,我们知道,父进程与子进程是独立的,互不干扰的,所以当子进程想要更改val时,会发生写时拷贝,系统会在物理内存上新开辟一个空间,并将val拷贝过去,将这个物理内存空间交给子进程,子进程进行更改,所以实际上父进程和子进程的val在物理内存地址上实际是不一样的,但是父子进程的val的虚拟地址是一样的,所以在用户层面我们取到的地址是一样的,只不过通过页表的不同映射关系,父子进程得到了不同的val值
阶段性全过程理解:
在我们创建一个进程时,系统会先创建对应进程的PCB,PCB中包含了一个mm_struct的结构体,它就是所谓的虚拟地址空间,它的内部会对内存(虚拟)进行区域划分(划分成我们以前理解的空间样式,比如mm_struct使用start_code,end_code,start_data,end_data等进行区域划分),然后给代码数据对应的内容进行地址分配,数据和代码所分配到的这个地址就是虚拟地址,然后将这些虚拟地址填入到页表的一列中,当系统将该进程对应的代码和数据加载到物理内存时,会将代码和数据对应的物理内存的地址填入到页表的另一列中,于是虚拟内存地址就和物理内存地址就有了一一映射的关系,于是我们就可以通过虚拟内存地址找到实际存储的物理内存地址

三.虚拟地址空间
虚拟地址空间可以用一个例子来理解:虚拟地址空间其实就是系统给每一个进程画的一张大饼,让每一个进程都认为自己有4GB的物理内存或者都认为自己在独占内存,实际上系统只会给每个进程先分配一小段内存,然后根据实际所需物理内存大小再灵活调整(因此物理内存上并没有什么区域的划分,交给进程的内存也可能不是连续的,由系统分配)
由6个问题理解虚拟地址空间!!
问题
问题1.虚拟地址空间mm_struct的空间划分在存储上是动态的还是静态的?
1.1.如何完成每个区域空间管理的?
问题2.进程与虚拟地址空间,页表之间的对应关系是怎样的?
问题3.程序启动时,先创建PCB还是先加载代码和数据?
3.1 缺页中断
3.2 一个进程可不可以只有PCB在内存上
问题4.mm_struct初始化是怎么初始化的?初始化的值从哪来?
问题5:如何理解挂起?
问题6:为什么要有虚拟地址空间?
问题1 && 1.1:
是动态的,mm_struct本身内部记录的是对整个虚拟地址区域的划分,比如代码区,已初始化数据区,未初始化数据区的起始地址,结束地址等,对存储虚拟地址的管理实际上是通过很多个vm_area_struct(VMA)管理的(先描述!),其内部会记录当前段的起始地址和结束地址等数据,然后用链表的方式连接起来(再组织!),因此每个区域的数据大小可以通过VMA来灵活调整
问题2:
一个进程有一个自己的虚拟地址空间,有一套自己的页表!
问题3 && 问题4:
全过程理解:
执行一个程序前,系统会先在内核创建一个对应的PCB,PCB内部的mm_struct先初始化,此时只是对虚拟空间的边界进行划分,VMA并没有被创建,在后来根据需要先对可执行文件进行解析,根据编译好的文件创建VMA,并将虚拟地址填入到页表中,然后当程序真正被CPU调度时,会发生缺页中断,系统将对应的代码和数据加载到内存上,然后再将代码和数据的物理内存地址填到页表上,再让CPU调度执行
有了VMA,我们也可以理解为什么可以malloc申请多段的堆空间了,本质上是在堆对应的区域上创建多个VMA(进一步对区域划分)
整个过程可以理解为“开一家书店”
先办营业执照→画规划图→根据规划图创建分区 + 贴分区标签→顾客来取书时→放书 + 填映射表
创建task_struct -> 初始化mm_struct -> 创建对应的VMA + 填页表 -> CPU调度执行 (缺页中断) -> 数据和代码加载到内存 + 填页表

3.1缺页中断:
在CPU调度执行时,页表上有虚拟地址但没有物理内存地址,此时CPU并不能通过虚拟地址找到实际的物理内存地址,这时发生的中断就叫做缺页中断
3.2 一个进程可不可以只有PCB在内存上 :
可以,当物理内存空间不足时,可以只创建task_struct,在CPU调度时发生缺页中断,加载到内存上再调度即可
问题5,如何理解挂起?:
物理内存空间不足时,会先将在硬件等待对列中进程的代码和数据唤出到磁盘的swap分区中,在硬件准备好,CPU调度时发生缺页中断,再从磁盘中唤入即可
问题6:为什么要有虚拟地址空间?:
a.将地址从“无序”变“有序”
b.地址转换的过程中,系统可以对你的地址和操作进行合法性判定,进而保护物理内存!
野指针:在使用野指针访问时,系统会判断指向哪个分区的,如果出错,系统就可能直接杀掉这个进程,即使不出错,编译器也会以以warning提醒
char* str = "helloworld"; *str = 'H' 为什么在字符常量区写入,就会崩溃?str记录的是h的地址,h在字符常量区,不可被修改,所以在该区域写入,系统在查找页表的时候,根据权限拦截了!
c.让进程管理和内存管理,进行一定程度的解耦合(进程和内存之间通过页表连接)!!

2129

被折叠的 条评论
为什么被折叠?



