坐井观天的:进程 | 虚拟内存 | 虚拟地址( 二 )


坐井观天的:进程 | 虚拟内存 | 虚拟地址

文章插图
 
好了,这可能就是你永远弄不清楚:“线程”和“进程”的原因,因为,这不仅仅是:一个软件问题,更是一个 MMU 的问题 。以后你再跟人讨论“线程”、“进程”的时候,一定要先问一下:有 MMU 吗?
 
总结
  1. 进程就像一只井底之蛙,虽然看上去,它可以读/写整个64位(假设CPU是64位的)的虚拟内存空间:void write_memory()
    {char*p = 0;
    for(unsigned long offset = 0; offset<= 0xFFFFFFFFFFFFFFFF; offset++)
    {*(p + offset) = 0x55;
    }} 但天到底有多大,真实的物理内存空间到底有多少?除了操作系统和MMU,没有人能知道 。
  2. 进程间的空间隔离,让进程之间的信息共享没有线程那么方便,但也大大提高了整个系统的安全性;再也不会因为某一个应用程序的崩溃,导致计算机重启 。还记得红白机上的reset按键吗?

坐井观天的:进程 | 虚拟内存 | 虚拟地址

文章插图
 
任何一个游戏程序的崩溃,都需要通过reset来重启/恢复系统 。
3. 进程间的空间隔离,让恶意程序无法再扫描整其他程序的内存或整个物理内存,任何程序只能在自己的一亩三分地里面干活 。通过游戏修改器,玩《仙剑奇侠传》的日子,不会再有了 。
坐井观天的:进程 | 虚拟内存 | 虚拟地址

文章插图
 
这样看来:生活在“井”里,也没有什么不好 。
 
热点问题Q1:谁在分配:虚拟地址?
A1:程序员在代码中编写的:任何变量、函数、数据结构,在编译过程中,都会被编译器安排了一个内存地址,这个地址就是虚拟地址 。
 
Q2:虚拟内存的好处?
A2:好处是:编译器在生成可执行程序时,可以更加自由的分配:代码中变量的内存地址,不用关心它在实际运行环境中,应该是多少?也不用关心运行环境的内存是否够用 。
相同的 exe文件,同时运行2次,也不用担心它们同名的变量或函数,会在内存中重叠在一起 。因为它们都用的是虚拟地址,无论外表多么相似,都可能被分配在不同的“物理地址”上 。
此外,当程序所需的内存大于计算机的实际内存时,虚拟内存机制可以用硬盘来给内存“扩容” 。
 
Q3:我电脑的内存有8GB,那跑在该电脑上的程序,其虚拟地址空间,也只能有8GB吗?
A3:虚拟地址的空间大小,取决于CPU的位数,32位CPU对应的虚拟地址空间为:0~0xFFFFFFFF(4GB),64位CPU对应的虚拟地址空间为:0~0xFFFFFFFFFFFFFFFF(16384PB),它们跟真实的物理内存大小,没有关系 。
 
Q4:为什么我执行实例代码的时候,输出的 a 的内存地址总是在变化?
A4:新版本的linux对虚拟内存进行了保护,作了随机化处理,为了达到文章所述的效果,需要取消这种随机化处理 。请在运行程序之前,在命令行中输入如下命令:
echo 0 > /proc/sys/kernel/randomize_va_space



推荐阅读