编程中的虚拟地址空间

3
我对虚拟地址空间的含义感到困惑。在32位机器上,一个进程可以寻址2^32个内存地址。那么每个进程的虚拟地址空间是否都是2^32(4GB)?下面是一个进程虚拟地址空间的快照。它是否可以增长到4GB?在这样的系统中,进程数量是否有限制?
4个回答

3
是的,在32位系统上,每个进程的虚拟地址空间都是4GB(232字节)。实际上,实际使用的虚拟内存很少,对应于处理器缓存、物理内存或磁盘(或计算机决定放置东西的任何其他地方)中的位置。
理论上来说(这种行为在常见操作系统中非常普遍),如果操作系统决定将无法适应物理内存的所有内容都放到磁盘上,那么进程实际上可以使用所有的虚拟内存,但这会使程序变得极其缓慢,因为每次尝试访问未缓存的某个内存位置时,都必须从磁盘中获取它。
你问的图片是否可以增长到4GB。实际上,你给出的图片已经占用了全部4GB。这是一种将进程的4GB虚拟内存分成不同部分的方法。另外,如果你想到堆和栈“增长”,它们实际上并不增长;在该分区布局中,它们有一定量的内存分配给它们,并且只是根据需要利用该内存(堆维护已使用和未使用内存的数据结构,栈移动指针等)。

如果操作系统决定将无法放入物理内存的所有内容放入磁盘中...请原谅我,但是难道现代所有桌面/服务器操作系统不都是这样做的吗(Windows、OS X、Linux、BSD)?(也就是说,除非您明确禁用该功能。) - Dietrich Epp
@DietrichEpp 是的,但重点是在于“一切”,我不想说某件事情肯定是这样的,因为实际上计算机可以自己决定做什么。 - Seth Carnegie
除了将数据放在磁盘上,如果数据无法放入内存,它还会做什么?(假设数据尚未存储在磁盘上。) - Dietrich Epp
@DietrichEpp 它可能会停止尝试并给出内存分配错误。 - Seth Carnegie
Linux不会这样做。如果您请求的内存超过了可用内存,它将终止一个进程以为您腾出空间,但它不会返回错误。 - Dietrich Epp
显示剩余3条评论

3

这个能扩展到4GB吗?

地址空间的大小受唯一指针值的数量限制。对于32位处理器,32位值可以表示2 ^ 32个不同的值。如果允许每个这样的值寻址不同的字节内存,那么你将得到2 ^ 32字节,相当于四千兆字节。

因此,是的,进程的虚拟地址空间理论上可以增长到4GB。然而在现实中,这也可能取决于系统和处理器。如下所示:

然而,在Pentium类处理器上无法达到这个理论最大值。其中一个原因是段值的低位编码了关于选择器类型的信息。因此,在65536个可能的选择器值中,只有8191个可用于访问用户模式数据。这会使你降到32TB。

请注意,从系统中分配内存有两种方法。您可以使用C的malloc(您的问题标记为隐式地为您的进程分配内存,当然也可以显式地映射文件字节。

这样的系统中是否存在进程数量限制?

一个进程包括一个或多个实际上在进程中执行代码并由内核线程对象表示的线程(技术上说,进程不运行,线程运行)。

根据此处进行的一些测试,具有2GB默认地址空间的32位Windows XP系统可以创建大约2025个线程:

Thread Limit of 2025

然而,在64位Windows XP上分配了4GB地址空间的情况下,32位测试限制创建了接近3204个线程:

32bit test limit on 64 bit XP created 3204 threads

然而,确切的线程和进程限制极其不确定,这取决于很多因素。线程指定它们的堆栈大小的方式,进程指定它们的最小工作集的方式,可用的物理内存量以及系统提交限制。无论如何,在现代系统上,你通常不需要担心这个问题,因为如果你的应用程序真的超过了线程限制,你应该重新考虑你的设计,因为几乎总是有其他合理的方法来实现相同的目标。


在Vista 64上运行32位应用程序-我的当前记录是,在一个应用程序中使用了4000个线程(总共超过5000个),没有问题(最大堆栈大小设置为128K)。 - Martin James
只是为了好玩,我将堆栈设置为65536,并且可以在一个应用程序中创建5000个线程。尝试创建6000个线程会导致“线程创建错误”异常框 :(。 - Martin James
有没有人在非Windows NT机器上计算最大线程数?我无法在任何地方找到相关信息。 - ApprenticeHacker

2
你读过维基百科的虚拟内存, 进程, 地址空间页面吗?
你读过哪本关于高级Unix编程高级Linux编程的书?
通常,地址空间是有效的段的集合(在你的图中不是蓝色的部分)。
还可以参考mmap(2)execve(2)页面。
在Linux系统上尝试一下。
cat /proc/self/maps

并且

cat /proc/$$/maps

更好地理解一点。
另请参阅这个问题这个。阅读操作系统:三个简单的部分 当然,内核能够设置一些限制(也请参阅setrlimit(2)系统调用)。它们是资源约束(交换空间、RAM等)。

-1

回答被忽略的部分...

进程数量是有限制的。内核在虚拟地址空间中保留了所有进程数据结构(否则您将无法在每个进程中访问内核),这些数据结构需要一些空间。例如,如果有1GB可用于此数据,并且每个进程在内核中只需要4KB页面,则最多可以达到大约250,000个进程。实际上,这个数字通常要小得多,因为事情更加复杂,并且为每个进程保留了各种物理内存。有关详细信息,请参见Mark Russinovich在Windows中进程和线程限制的文章


“which is shared, otherwise you wouldn't be able to access the kernel in every process”: 我不明白你所说的“它是共享的”是什么意思。在谁之间共享? - Kindred
例如,如果这个数据只有1GB可用,那么在哪里?是哪个数据? - Kindred
@ptr_user7813604 内核的虚拟地址空间是共享的。它存在于每个进程的虚拟地址空间中。这部分的大小是有限制的(在4GB中为1或2GB)。因此,例如,如果您使用4KB的内存页面来描述每个进程状态,并且您只有1GB的内核VAS部分,则最多可以有250K个进程。 - Alexey Frunze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接