进程地址空间

1.分页和虚拟地址空间

每个task_struct都有虚拟地址空间,在C上面的指针都是虚拟地址,代码和数据加载到物理内存是随机找位置加载的,而在虚拟地址空间会形成一个虚拟地址,而页表就是把虚拟地址和物理地址连在一起的桥梁,页表左边放虚拟地址对应的右边则放物理地址,每一个虚拟地址都对应一个物理地址,在虚拟地址空间开辟的空间是连续有序的,而在物理内存则是随机的。

虚拟地址的大小是一个字节的,但是一节空间是四个字节,所以虚拟地址是四字节最小的哪一个字节,32位机器有2^32个地址。

之前遗留问题

fork函数创建子进程,在子进程的代码里修改全局变量,父进程打印这个全局变量,父子进程的全局变量不一样的结果,创建的子进程会继承父进程的代码和数据,页表也会继承,有一样的虚拟地址,所有打印地址是一样的,但是子进程修改变量时,是错误的,因为当数据共用时,权限会变成只读,也会触发写时拷贝,会在物理地址重新找一块地址拷贝原来的数据到这里,然后再给子进程修改数据,所有父进程和子进程的虚拟地址是一样的,物理地址不一样。

2.虚拟地址与进程地址空间

例子1

有一个大富翁,他四个孩子,他跟第一个孩子说大学成功毕业后,他死后的财产都给你,第二个孩子说高中成功毕业,死后的财产给你,三孩子说初中成功毕业后,死后的财产都给你,四孩子则同样,当大富翁只有一份财产,所以他给四个孩子都画了一个饼,这些饼就是虚拟地址空间,孩子则是进程,饼也要管理,先描述再组织。

例子2

有一个桌子,小明和小华做一起,因为有俩个人所以要划分区域,谁越界就会被另一方打,小明在自己的区域可以为所欲为,小华也是,这个桌子就是地址空间,对桌子进行描述,属性就可以有小明占了多少大小,小华有多少位置等,而区域也可以变的,把小明的占领面积变大则桌子上小明的空间就大了,由此引出虚拟地址空间的本质是一个数据结构struct mm_struct结构体,有不同区域的开始和结束位置(整型),这样就可以通过这个结构体知道不同区域的开始和结束的位置在那里。

3.虚拟内存管理

描述Linux下进程的地址空间的所有信息的结构体是mm_struct(内存描述符)。每个进程只有一个mm_struct结构,在每一个进程的task_struct结构中,有一个指向该进程的结构。

可以说mm_struct结构是对整个用户空间的描述,每一个进程都会有自己独立的mm_struct,这样每一个进程都会有自己独立的地址空间才能互不干扰。下图是task_struct到mm_struct,进程的地址空间分布情况:

Linux内核使用vm_area_struct结构来表示一个独立的虚拟内存区域(VMA),由于每个不同质的虚拟内存区域功能和内部机制不同,因此一个进程使用多个vm_area_struct结构分别表示不同类型的虚拟内存区域。

4.为什么要有虚拟地址空间

当程序同时运行多个程序时,操作系统是如何为这些程序分配内存的?例如某台计算机总的内存大小是128M,现在同时运行俩个程序A和B,A需要占用内存10M,B需要110M。计算机在给程序分配内存时会采用这样的方法:先将内存的前10M分配给程序A,接着再从内存中剩余的118M中划分出110M分配给程序B。

这种分配方法可以保证程序A和B都能运行,但是这种简单的内存分配策略问题很多。

安全风险

每个进程都可以访问任意的内存空间,这也意味着任何一个进程都能够去读写系统相关内存区域,如果是一个木马病毒,那么它就能随意修改内存空间,让设备直接瘫痪。

地址不确定

编译完成后的程序是放在硬盘上的,当运行的时候,需要将程序搬到内存中去运行,如果直接使用物理地址的话,无法确定内存使用到那里了,也就是说拷贝的实际内存地址每一次都是不确定的

效率低下

如果直接使用物理内存的话,一个进程就是作为一个整体操作的,如果出现物理内存不够用的时候,一般的办法是将不常用的进程拷贝到磁盘的交换分区中,以便腾出内存,但是如果是物理地址的话,就需要将整个进程一起拷走,这样的话在内存和磁盘之间拷贝的时间太长,效率低下。

虚拟地址空间的解决

地址空间和页表是OS创建并维护的,意味着使用地址空间和页表进行映射,也一定要在OS的监管之下进行访问,也顺便保护了物理内存中所有的合法数据,包括各个进程以及内核的相关有效数据

因为有地址空间的存在和页表的映射存在,物理内存中可以对未来的数据进行任意位置的加载,物理内存的分配和进程的管理就可以无相关,进程管理模块和内存管理模块就完成了解耦合

因为地址空间的存在,所以在C/C++语言上new,malloc空间的时候,其实是在地址空间上申请的,物理内存甚至可以一个字节不分配。当真正进行对物理地址空间访问的时候,才执行内存的相关管理算法,帮你申请内存,构建页表映射关系(延迟分配),这是由操作系统自动完成的。

因为页表的映射存在,程序在物理内存中理论上就可以任意位置加载。它可以将地址空间上的虚拟地址和物理地址进行映射,在进程视角所有的内存分布都可以是有序的。

5.进程管理和内存管理

当磁盘的可执行文件要加载到物理内存时,是先有task_struct,mm_struct和页表的,也就说说页表上面可以只有虚拟地址,而没有物理地址的,当查页表表时虚拟地址存在而没有物理地址时会先去磁盘中把代码和数据加载到物理内存中,然后虚拟地址有对应的物理地址,上面现象为缺页中断,挂起是进程在等待设备进程就绪,当内存不足时会进行换出,这里是把不用的物理地址给清空,保留虚拟地址,然后把要执行的物理地址放进来,等设备就绪时再把代码从磁盘换入,同时把物理地址重新填入。这样好处时物理地址的更替和虚拟地址无关,且可以把不用的换出,这里不是一整块的换出,而是换出的部分足够现在的所需的空间即可,因为物理地址是无序的,重新加载进来放那里都可以,跟虚拟地址完成映射关系就行。

页表记录此地址的权限

还需要知道页表的额外功能,还有记录权限的,表示这个地址的权限,比如字符串常量区是不可修改的,是因为对应的权限是只读,所以把这块地方的内容修改会权限拦截的。

相关推荐
Smark.10 分钟前
Gurobi基础语法之 addConstr, addConstrs, addQConstr, addMQConstr
算法
S-X-S28 分钟前
算法总结-数组/字符串
java·数据结构·算法
努力学习java的哈吉米大王1 小时前
数据结构-队列
数据结构
Joyner20181 小时前
python-leetcode-从中序与后序遍历序列构造二叉树
算法·leetcode·职场和发展
因兹菜1 小时前
[LeetCode]day9 203.移除链表元素
算法·leetcode·链表
LNsupermali1 小时前
力扣257. 二叉树的所有路径(遍历思想解决)
算法·leetcode·职场和发展
雾月551 小时前
LeetCode LCR180文件组合
算法·leetcode·职场和发展
萌の鱼1 小时前
leetcode 2080. 区间内查询数字的频率
数据结构·c++·算法·leetcode
Tisfy1 小时前
LeetCode 0541.反转字符串 II:模拟
算法·leetcode·字符串·题解
CM莫问3 小时前
什么是门控循环单元?
人工智能·pytorch·python·rnn·深度学习·算法·gru