网站建设与管理学习什么,优秀地方门户网站系统,网络营销方式包括哪些,铁岭市做网站【进程概念④】#xff1a;进程地址空间(虚拟内存与物理内存#xff09; 一.进程地址空间二.分页与虚拟地址①.what②.how③.why 三.页表细节①.标志位②.缺页中断 四.总结意义 一.进程地址空间
你觉得我们代码中写的数据都在哪存储着呢#xff1f; 在内存里存着#xff0… 【进程概念④】进程地址空间(虚拟内存与物理内存 一.进程地址空间二.分页与虚拟地址①.what②.how③.why 三.页表细节①.标志位②.缺页中断 四.总结意义 一.进程地址空间
你觉得我们代码中写的数据都在哪存储着呢 在内存里存着确实是在内存里存储着那你知道数据存在内存的哪里呢 你以前肯定听过栈堆静态区等等的。都是在内存上划分的。 比如局部变量是在栈上开辟的动态申请的空间是在堆区申请的全局变量是在全局区(这里又分成初始化数据和未初始化数据)代码都是存在代码段的。 对于栈呢它是向下增长也就是向地址减少的地方增长的对于堆呢它是向上增长也就是向地址增长的方向增长的。 所以在我们没有学习进程地址空间时我们对于内存的印象就是如上图所示。而学习进程地址空间后你就会发现其实这个并不是真正的内存。
理解进程地址空间我们先理解一下下面这个问题 【问题】我们知道fork()创建进程时会返回两个值为什么同一个变量可以接受两不同的值呢
#include stdio.h
#include unistd.h
#include stdlib.h
int g_val 0;
int main()
{pid_t id fork();if(id 0){perror(fork);return 0;}else if(id 0){ //child子进程g_val100;//将全局变量改成100printf(child[%d]: %d : %p\n, getpid(), g_val, g_val);}else{ //parent父进程printf(parent[%d]: %d : %p\n, getpid(), g_val, g_val);}sleep(1);return 0;
}我们在全局定义一个变量g_val.并初始化为0. 然后利用fork函数创建两个进程一个为子进程一个为父进程子进程先执行在子进程中将全局变量修改成g_val修改成100.并打印它的值和地址。在父进程中修改全局变量的值打印它的值和地址。最后结果显示子进程和父进程中的全局变量值并不一样而地址确实一样的这是为什么呢 我们可以猜想 1.变量内容不相同父子进程中输入的变量肯定不是同一个变量。 2.但是父子进程中变量的地址却又相同这说明这个地址肯定不是物理地址因为物理地址只能一对一不存在一对多的情况。 其实这里的地址是虚拟地址在Linux中我们用c/C语言所看到的地址都是虚拟地址都不是物理地址物理地址用户是看不到的。
二.分页与虚拟地址
其实呢进程并不是直接与物理内存进行交互的中间还存在着一个叫做进程地址空间的对象。进程地址空间其实就是虚拟内存而物理内存才是真正的内存除了进程地址空间外中间还存在一个叫页表的对象它是用来将虚拟地址转换映射成物理地址的。页表中其实有很多标识位比如权限位和判断位等等。最主要还是它可以将虚拟地址映射到物理地址上去页表的左边存的都是虚拟地址页表的右边则是存着物理地址。这就形成了映射。当进程访问内存时先访问的是虚拟内存然后才是根据页表映射转换到物理内存。 当使用fork()创建子进程时子进程也需要进程地址空间而子进程的进程地址空间是继承父进程的也就是直接从父进程那拷贝过来的。 子进程的页表其实也是从父进程那拷贝过来的所以父子进程默认情况下数据和代码指向都是一样的也就印证了父子代码共享数据一般也是共享的除非发生写实拷贝。 好的我们现在再转回到问题上去为什么fork()返回的两个值可以存在同一个变量里为什么父子进程的变量值不相同但地址却相同呢
首先我们要确定的是他们这里面发生了写入数据导致发生写实拷贝了。fork()返回返回值时是不是写入改变全局变量的值是不是写入 那么写时拷贝发生了什么呢 写时拷贝父子进程先写入的就会将要访问的数据拷贝一份重新开辟内存创建变量。所以关键在于重新开辟了一块空间了。 这时子进程的物理地址就不再指向父进程原来的变量位置而是指向一块新开辟的空间了。但是这个写时拷贝的过程并不影响进程虚拟地址。 所以我们就可以知道为什么父子进程中同一个变量值不同了是因为变量的物理内存不同它们的地址却相同是因为写时拷贝不影响虚拟内存。
①.what
什么是进程地址空间呢 什么是32位机器呢就是它有32个总线。每一根地址总线只有01表示。那么可以表示的范围就是0–2^32种了。而这就是该机器下所能表示的内存范围至于地址空间是什么就是地址总线排列组合形成的地址范围能访问的最大范围也就是一段数据(地址)的范围。
②.how
如何理解地址空间上的区域划分呢区域又是如何进行划分的呢 我们可以假设有一块连续空间被小胖和小芳两个人共同使用但是小胖总是喜欢跑到小芳的位置上吃零食睡觉小芳这能忍吗这当然不能忍了。所以小芳就提出划分区域定出一个三八线出来不给小胖逾越。那么你想一想应该如何帮助小芳进行区域的划分呢 我们可以直接定义一个桌面区域结构体它里面包含着四个变量小胖的起始位置和小胖的终点位置小芳的起始位置和小芳的终点位置。这里通过这个结构体对象我们就可以对该区域进行划分小芳想要公平公正一些就各自一人一般的区间谁也不能逾越。
所以结构体对象就可以这样定义
struct desk_area justic{ 1,50,51,100 };所以对于每一个进程来说除了要有PCB外还需要进程地址空间。 在进程创建时操作系统处理创建一个PCB对象给进程还要创建一个进程地址空间对象给进程。并且操作系统还要对这个地址空间进行管理至于如何管理呢先描述再组织
操作系统会像上面一样首先会对进程地址空间进行描述将空间区域的划分边界变量确定下来。操作系统不是直接在PCB里创建进程地址空间对象而是在PCB里存储一个指向进程地址空间的指针然后再利用数据结构进行管理。 1.其实所谓的进程地址空间本质上就是一个描述进程可视范围的大小就是进程可以看到内存的范围。 2.地址空间里会存在区域的划分划分的手段就是将线性地址发个成不同区的start和end。 3.进程空间本质也是内核的一个数据结构对象类似于PCB。地址空间也是需要被操作系统管理的。 在进程PCB里存着一个指针叫做struct mm_struct的对象指针。这个对象指针就是指向进程地址空间的。 ③.why
为什么要有进程地址空间呢 在这里我们对进程的理解更深入了进程的概念仍然是内核数据结构自己写的代码和数据。只不过这里的内核数据结构 除了PCB对象外还有进程地址空间对象。 在没有进程地址空间以前进程都是直接访问物理地址的这很危险进程管理和内存管理两个直接出现了强耦合。当内存管理出现了问题进程就挂了比如如果是越界访问进程就直接挂掉但就怕有人将物理地址空间修改了内容改变了这可能会影响其他进程。 而现在呢有了进程空间地址我们不再直接跟物理内存进行访问而是通过虚拟内存进行访问如果出现了问题虚拟内存的机制会进行拦截除了的并不会到达物理内存这样就大大的保护了物理内存了。 1.所以进程地址空间可以让我访问内存时增加一个转换的过程在这个转换的过程中可以对我们的寻址请求进行审查一旦出现异常访问直接拦截该请求不会到达物理内存保护物理内存。 2.可以让进程一统一的视角看待内部。因为物理内存是没有区域划分的是可以随意任何地方开辟空间的而虚拟内存则是划分区域的最后可以让无序变有序。 3.减少了强耦合一旦内存管理出现问题会影响其他进程。 三.页表细节
①.标志位
页表是在哪呢在CPU的一个叫cr3的寄存器里里面存储着页表的起始地址。 我们要理解当进行需要使用页表时肯定表面该进程正在运行使用中那么肯定在CPU上运行着所以进程直接通过CPU上的寄存器就可以找到该进程的页表。 在深入理解页表之前我们先理解一个问题 【问题】为什么只读区的数据只读不给写的静态成员为什么不能修改呢代码是只读的为什么呢 对于物理内存来说没有只读概念都是可访问的所以实现这个操作的关键在页表。
在页表中除了虚拟内存映射物理内存外还有一个标识位。 表示该内存是否可以读写r表示只读rw表示可读可写。 所以对于代码区域的或者静态区的虚拟内存确实映射到物理内存上了但页表还给它进行了标识r表示只读。这样该数据就只能是只读状态不可写。
②.缺页中断
我们知道进程挂起时会将进程的代码和数据先放入磁盘中省出空间给CPU使用那么我们如何确定进程的代码和数据被放入磁盘里了呢 对于虚拟内存地址都可以先将加载到页表里而物理内存可以先不加载进去然后页表里存在一个标志位用来表示该物理内存是否存在0表示不存在1表示存在。
所以当CPU需要访问某个数据时首先会根据页表从虚拟地址转换到物理地址如果发现页表里没有加载该数据的物理地址页表里的标识位也为0.操作系统会给这个数据申请内存然后将申请的内存地址加载到页表里并将标识位改成1然后CPU再重新访问页表映射到物理地址。这时就可以正常访问数据了这个过程叫做页表中断。 所以对于进程来说一开始没有数据加载到内存里也是可以创建PCB内核数据结构的等当真正访问数据时再将数据加载进来。 并且就算程序运行起来了数据加载进来了也不代表所有的数据都加载进来。
写时拷贝的本质也就是发生了缺页中断。 四.总结意义
当发生缺页中断时内存会重新申请页表的物理地址会被填充内存的释放等过程跟进程是没有关系的进程不需要关系这些问题。 进程只需向虚拟内存申请空间释放空间。如果页表中的物理地址不存在就会发生缺页中断自动调用内存管理的功能去向内存中申请空间。 所有进程地址空间和页表的存在使得进程管理根本不需要关心内存管理。 1.总结进程地址空间意义 2.什么是统一的视角看待内存呢 3.并且我们可以从更深层去阐明进程之间为什么存在着独立性虚拟地址可以完全一样但物理地址不同 4.进程地址空间的存在使得物理内存不再被看见