虚拟内存
-
首先要理解操作系统不能把真实的物理内存直接分配给进程使用,如果真的这样做,那么会面临严重的安全问题,进程可以根据或得到的真实物理内存地址,通过指针访问其它进程的内存进行破坏,甚至会影响操作系统的安全,所以才会引入虚拟内存的概念
什么是虚拟内存:
-
虚拟内存是操作系统对进行内存空间地址进行管理的一套精心设计的逻辑层面的内存空间概念
-
在32位系统下,操作系统规定给每个启动的进程拥有4G大小虚拟内存,但是这4G的虚拟内存不能直接使用的,其实就是系统给进程画的饼,当进程真正要存储数据需要使用内存时,系统会把一部分虚拟内存与物理内存进行映射,必须进行映射后的虚拟内存才能正常使用
-
如果非要使用没有映射过的虚拟内存,操作系统一定会在运行时产生段错误
用户空间与内核空间:
-
每个进程的4G虚拟内存中,根据使用者不同分为两个部分:
用户空间:
-
[0x00000000~0xC0000000]部分,有3GB大小,在经过系统的映射后,在应用程序中使用,但是程序不能直接访问内核空间的代码和数据,但是可以通过系统调用(API)让当前进程从用户态进入内核态,间接地与系统内核进行数据交互
内核空间:
-
[0xC0000000~0xFFFFFFFF]部分,有1GB大小,只有操作系统才能使用,里面存储的是操作系统为服务进程与该进程进行交互所必需的相关数据,内核空间又操作系统来管理,内核空间不会随着进程的切换而改变
-
但是用户空间对应不同的进程,一旦进程切换,用户空间使用的物理内存也会被内核随之切换,这样就确保了不同进程的用户空间是完全独立的。
-
因此不同进程之间使用虚拟内存进行交互数据是毫无意义的,所以下面两个程序直接通过虚拟内存地址交互数据是毫无意义的
// 程序A #include <stdio.h> int main(int argc,const char* argv[]) { int num = 123456; printf("%lu\n",(unsigned long)&num); getchar(); } // 程序B #include <stdio.h> int main(int argc,const char* argv[]) { int* p = NULL; unsigned long num = 0; scanf("%lu",&num); p = (int*)num; printf("%d\n",*p); // 无法访问程序A的num内存 }
-
在内核态下,进程运行在3~4GB空间范围内,此时CPU可执行任何指令,代码不受任何的限制,可以自由地访问任何有效地址,甚至可以直接访问端口
-
在用户态,进程运行在0~3GB空间范围内,此时执行的代码要受到一定的限制,CPU会做很多的检查,例如:检查进程只能使用映射过的虚拟地址等
进程使用虚拟内存的好处有哪些?
-
操作系统给每个进程分配4GB的虚拟内存,可以让进程之间进行隔离,避免进程之间相互影响、破坏
-
操作系统把4GB的虚拟内存划分成用户空间(0~3GB)和内核空间(3~4GB),可以让进程与操作系统之间进行隔离,避免进程去破坏操作系统的正常运行
-
通过给进程使用虚拟内存,避免暴露真实的物理内存地址,也是对操作系统的保护
-
操作系统还可以让磁盘上的文件与虚拟内存进行映射,当物理内存不够用时,还可以通过映射磁盘来替代,虽然速度慢一些,相当于能让用户使用比真实物理内存更大的空间