一个进程中每个数据的虚拟地址是固定的
不一定,可能是动态变化的,比如堆栈,固定的一般指的是代码段的部分(但代码段其实也可能是可变的)
但受其它进程占用真实内存空间的影响,虚拟地址映射到的物理地址是不断变化的
通常来说,操作系统会优化内存申请,尽量保持连续,不连续的内存对于操作系统来说也是不友好的。同时,操作系统不会频繁更改虚拟地址到物理地址的映射,除非是内存十分紧张。频繁的更改映射会降低性能。
所有进程的虚拟内存加起来远大于真实的内存大小,
虚拟地址空间通常确实是远大于真实物理内存,但真正提交映射的虚拟地址,可能不会“远大于”。
所以每一时刻所有进程正在使用的虚拟内存是可以单射到物理内存的
如果正在使用的虚拟内存已经映射但没在物理内存里,会报缺页中断,操作系统会负责加载这部分内存。所以并不是所有已经被提交的内存都在物理内存里,可能大部分都不在。
考虑到多核的问题,那么真正意义上“正在被使用”的内存最多只有:4K (页大小) * (1代码页 + 1 数据页)* CPU核数,这个数量其实很小。
即使加上页表,加上中断管理、驱动等内容,这部分的内存也不大。
(1)这个虚拟内存与物理内存的映射关系储存在哪里?如果也储存在内存中,那么如何让这个映射表所占空间尽可能的小?
映射关系也保存在内存里,也就是“页表”,页表通常不会很大。
打开PAE的情况下,一个页表项占8字节,一个4K页可以保存512个页表项,映射512*4K=2MB的内存,相当于2M内存浪费4K,比例不到0.2%,并不高。如果不打开PAE,那么一个4K页可以保存1024个页表项,内存浪费比例不到千分之一。
况且还允许有2M页等更大的页存在,所以不用担心浪费的问题。
一个32位的地址空间有4G,但操作系统不需要对整个4G空间都做映射,页表是分级的,三级页表的顶级里,并不是每一个页表项都是可用的,如果顶级页表项(PDPTE)没有指向一个有效的子项(PDE),那么PDE往后的内容不再需要内存来存储页表。这样的话,如果映射连续的2M内存,只需要4K+4K+4K的页表就足够了。
同样的,我前面说了操作系统会倾向于分配更加连续的内存,不管是物理上的连续还是虚拟地址的连续,连续的内存占用的表项不会太多。
(2)如何控制每一时刻所有进程正在使用的虚拟内存的大小小于等于物理内存?
操作系统有换页算法,某一个物理页不用了,会换到磁盘上。页表中,并不要求所有的页表项都处于有效的状态。
物理内存不够用的话,把不经常使用的页换出去就可以了(LRU算法)
(3)操作系统完成相应的分配和调度,也需要占用内存,这个占用的内存空间大概有多大?
不需要多大,以Windows为例,Windows95只需要4M内存就可以运行。通常情况下内核页表和用户页表可能是分开的,内核页表一般是一次性分配的,如果用的少的话,3-4个页就够用了。页表的使用量跟物理内存大小有关,物理内存越大,页表的体积也越大。