(我的目标是现代Windows版本,如Vista,Win 7,Server 2003/2008 32位版本。)
http://blogs.msdn.com/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx
两个混乱,
用户空间的虚拟内存空间通常限制在2G,但是物理磁盘页面的存储量可能比2G大得多。 由于磁盘页面比虚拟内存页面多,因此理论上可以将多个磁盘页面映射到一个虚拟地址页面。 如果用户请求访问某个虚拟地址,如果多个磁盘页面映射到一个虚拟地址页面,内存pipe理器如何知道应该访问哪个磁盘页面?
不知道为什么有像byte []这样的数组必须使用连续的虚拟内存空间。 我想理论上即使我们只分配了500M的虚拟空间地址,我们也可以重新使用这样的虚拟空间地址来继续映射/取消映射磁盘页面文件,尽可能多的使用我们想要的,甚至大于2G。
有任何想法吗?
字节(或任何其他)数组必须使用连续的地址空间 ,在这种情况下是连续的虚拟地址空间。 这是一个可以使碎片成为问题的领域,实际上由于内存虚拟化而加剧。 由于这种系统系统固有的各种“重定向”以及使其高效的性能考虑因素导致实际分配映射到块(通常是页面)中的虚拟地址空间的物理地址空间。
所以请求一个10字节的虚拟地址空间块实际上可能导致整个4K页面被保留和映射。 由于页面内的物理内存必须是连续的,这可能导致整个4K的虚拟地址空间被“阻塞”。
可以在一个页面内放置多个小的分配(并且好的内存管理器将尝试实现这一点),但是没有哪个地址空间实际上被保留在超出严格要求的地方。 考虑在起始fa页面分配单个字节,然后是4K-2个字节,接着是另一个单个字节。 这占据(有效)整个页面。
考虑如果中间分配不再是必要的,从而被释放。 在“top”和“tail”值被释放或移动到其他地方之前,虚拟地址空间中已经创建了一个只能由<4K-1字节大小填充的空隙。 如果足够的这种事情发生在虚拟地址空间的连续区域收缩比真正使用的内存的实际总量要快得多。
你是正确的,没有任何东西阻止你,用户,映射(限制在32位土地)地址空间到CPU / OS支持更大的磁盘或内存空间。 一些芯片通过像PAE这样的机制使物理地址空间超过4GB成为可能。
Windows本身提供了一个API来处理大部分“改变你的地址空间映射到一个更宽的池(通过像PAE,运行WoW64,磁盘或混合物)的不同窗口'的方面。 这被称为AWE 。 但是像这样的机制已经存在多年了(正如那些记忆EMS的日子,还有传统记忆或者分段记忆的日子)。
即使没有CPU和操作系统支持,您仍然可以通过各种技术手动完成(见下文)。
在这个窗口中,很多复杂的方面都被有趣的Raymond Chen所处理。
(某些版本的Windows有一个开关,可以为用户程序启用3G,但由于原理相同,我们将忽略这一点。
32位程序只能访问4G的内存,因为这是32位的最大指针。 当一个程序运行时,一些内存空间被映射到自己,另一些被映射到操作系统。 否则,当调用操作系统时,操作系统代码不能同时看到自己的内存和程序内存。
所以你的程序没有得到所有的内存,因此对连续分配的限制。
现在,不同的程序可以具有所有可寻址存储器的不同子集。 一些32位芯片允许物理上超过4G的内存,但仍然是,任何给定的过程,因为它是32位的,一次只能“直接”看到32位数据或4G,其中一些属于过程(2G )以及一些用于管理程序和其他程序的操作系统(2G)。
我可以给出这个简单的解释; 请参阅虚拟内存了解更长的技术说明。
Mark Russinovich写了很好的文章推动Windows的限制:虚拟内存 。 我认为你应该读清楚它是如何工作的。
进程可用的总虚拟地址空间为4GB。 这个上面的2GB是所有进程通用的,只能被系统级组件访问。 较低的2GB是每个进程私有的,不共享。 这与RAM的大小完全没有关系。 可以有2GB以上的磁盘页面映射到用户进程。 由于2GB进程空间是私有的,所有进程的总地址空间将远远超过2GB。 即使在理论上,也不可能在同一个进程中将多个磁盘页面映射到一个虚拟地址。