转自:http://blog.chinaunix.net/uid-20384269-id-1954602.html
首先,内存访问和管理是一个跨越应用程序,操作系统,硬件平台的一个复杂过程,不能单纯的讲32bit系统就支持4G内存,从而认为这个过程只是OS和内存两者之间的关系
理论上:
32位系统,32bit的地址总线位数,寻址空间2^32B=4GB。 64位系统,寻址空间2^64。
至于在实际应用环境中,对于有4G物理内存而OS最多只能识别3G的情况,主要是主板的问题,丢掉的内存被PCI设备占用。
64位的主板支持PCI hole memory remapping,可以把这部分内存重新映射到高位的物理地址空间。
32是可用的地址总线位数(地址总线可不只32位,系统是32位的,用不了那么多)。
每次CPU工作,地址总线就给个地址,32位每次只能决定一个,然后地址总线把32个0或1弄出来成一个0或1(当然,地址总线不仅仅只有这个功能),基本就相当于译码器了。32个或0或1排列,根据排列组合就是2的32次方,由于内存编址是按字节(C中狭隘的字节,8bit)来的,所以就是2的32次方个字节了,也就是4GB。
这里谈一下对于打开CPU PAE功能从而能扩展OS内存支持的原理:
物理地址扩展PAE)是指x86和x86-64处理器的一个特色,即如果操作系统提供适当支持,则可以在32位的系统中使用超过4G的内存PAE为Intel Pentium Pro及以上级别的CPU(包括除了总线频率为400MHz的这个版本的奔腾M之外的所有新型号奔腾系列处理器)所支持,其它兼容的处理器,如速龙(Athlon)和AMD的较新型号的CPU也支持PAE。
x86的处理器增加了额外的地址线以选择那些增加了的内存地址,所以支持的内存寻址大小从32bit增加到36bit。最大支持内存由4G增加到64G,32位的虚拟地址则没有变,所以一般的应用软件可以继续使用地址为32位的指令;
如果用平面内存模式的话,这些软件的地址空间也被限制为4G
[注]:"平面内存模式"
8086体系的CPU一开始是20根地址线, 寻址寄存器是16位, 16位的寄存器可以访问64K的地址空间, 如果程序要想访问大于64K的内存, 就要把内存分段, 每段64K, 用段地址+偏移量的方法来访问.后来386CPU出来之后, 采用了32条地址线, 地址寄存器也扩为32位, 这样就可以不用分段了, 直接用一个地址寄存器来线性访问4G内存. 这就叫平面模式.
操作系统用页表将这4G的地址空间映射到大小为64G的物理内存空间,而这个映射对各个进程一般是不一样的。这样一来,即使不能为单单一个程序所用,那些增加了的物理内存仍然可以发挥作用。
对于需要超过4G内存的应用软件来说,除了一般的PAE支持,还需要操作系统提供另外的特殊的技术。
在Windows上,这种技术叫做Address Windowing Extensions(AWE)。而在类Unix的系统上则有多种技术在使用,例如使用mmap()按需要把一部分文件映射到地址空间;但是,这还没有成为一个标准。
Linux内核从2.6版本开始全面支持PAE,这使得在32位的机器上可以访问64GB的内存。启用了PAE的Linux内核还需要同样支持PAE的CPU。从2008年起,很多一般的发布的Linux版本都默认使用启用了PAE的内核。
Solaris从版本7开始支持PAE。但是,版本7的那些没有专门支持PAE的第三方驱动程序在支持PAE的系统上可能会发生错误,甚至完全崩溃。不过现在都早已是soloaris 10的时代. 如今基本不会有什么问题。
【OS内存管理模式】
除了前面提及的平面模式外,还有如下两种
“保护模式”
386的线性内存访问功能只在一种叫"保护模式"的状态上使用, 在这种状态下, 一切程序都可以用线性地址(不分段)访问自己所拥有的4G的内存空间, 但是不能访问其他程序的空间. 如果有程序要访问不该访问的内存(一般只有病毒才会这么作), 就会出系统错误, CPU就用中断通知OS, 这样的进程会被OS发现, 并杀死, 不会影响其他程序.
在windows里常见的系统错误"某某内存不能读写"就是这种问题, 这都不是windows系统的问题, 而是一些程序的问题.
在这种情况下, 实际是CPU和OS一起保护了程序的内存, 因此叫做保护模式.
“实模式”
实际上内存是不可能有4个G的(见http://blog.chinaunix.net/space.php?uid=15724196&do=blog&cuid=1976044)而且是每个程序都要有4G的空间. 为了为每个程序都提供4G内存, 386及以后的CPU采用"页"的方式来管理内存, 把内存分为一个个的页, 页的物理地址与每个程序虚拟的4G线性地址的对应关系用一个表格保存。
程序用线性地址访问一块内存. 如果这个内存还没有用过, 就找一个内存页来假装涉及的线性内存段. 如果这个内存长期不用, 操作系统就把内存页存到硬盘上去, 就叫虚存交换文件.
如果这个内存所在的页已经分配过, 但是没有在实存里, 那么CPU就出现一个缺页中断, 此时就由操作系统把存储在硬盘上的交换文件里的页内数据读出来, 在实存中找一块写进去, 修改页地址和线性地址的对应表格, 然后请程序继续运行.
【页表结构】
在传统的32位的保护模式中,x86处理器使用一种两级的转换方案。在这种方案中,控制暂存器CR3指向一个长4K的页目录(page directory);页目录又分为1024个每个4K的页表(page table);最后页表又分为1024个每个长4K的页。
启用PAE(通过设置控制暂存器CR4的第5位来启用)会改变上面的方案。默认情况下,每页的大小是4K的。页表和页目录中的表项都从32位扩为64位(8字节)以使用附加的地址位。但是,页表和页目录的总大小不变。
所以,页表和页目录现在都只有512个表项。因为这变成了原来方案的一半,所以另外的一个级加了进来:CR3现在指向的是页目录指针表,即一个包含4个页目录指针的表。
页目录里的表项的第7位叫做PS(Page Size)。如果这个位设为1,则页目录的表项不再指向页表,而是指向一个2M的页。页目录里还有另外一个叫NX位元的标志位。它是第63位,表示No eXecute。
因为页表项最高的12位,要么是这种标识位,要么是和操作系统相关的数据,所以最多可有52位,在将来用于在252字节物理内存中寻址。
现在,x86架构只使用该52位中的36位。对于在长模式(long mode)中的x86-64处理器,PAE是必须的;其中使用了52位中的40位。
CPU对PAE模式的支持可以通过CPUID标志PAE来识别。
4种页表结构:
未启用PAE, 4 KB的页、未启用PAE, 4 MB的页、启用PAE, 4 KB的页、启用PAE, 2MB的页