【发布时间】:2012-03-19 16:45:16
【问题描述】:
我对虚拟地址空间的含义感到困惑。在 32 位机器中,一个进程可以寻址 2^32 个内存位置。这是否意味着每个进程的虚拟地址空间是 2^32 (4GB) ?
下面是一个进程的虚拟地址空间的快照。这可以增长到4GB吗?这样的系统中的进程数有限制吗?
【问题讨论】:
标签: c memory-management
我对虚拟地址空间的含义感到困惑。在 32 位机器中,一个进程可以寻址 2^32 个内存位置。这是否意味着每个进程的虚拟地址空间是 2^32 (4GB) ?
下面是一个进程的虚拟地址空间的快照。这可以增长到4GB吗?这样的系统中的进程数有限制吗?
【问题讨论】:
标签: c memory-management
地址空间的大小受唯一指针值的数量限制。对于 32 位处理器,一个 32 位值可以表示 2 ^ 32 个不同的值。如果您允许每个这样的值寻址不同的内存字节,您将获得 2 ^ 32 字节,即 4 GB。
所以,是的,一个进程的虚拟地址空间理论上可以增长到 4 GB。然而实际上,这也可能取决于系统和处理器。可以看出:
但是,奔腾类处理器无法达到这个理论上的最大值。一个原因是段值的低位编码有关选择器类型的信息。因此,在 65536 个可能的选择器值中,只有 8191 个可用于访问用户模式数据。这会将您降至 32TB。
请注意,有两种方法可以从系统分配内存,当然,您可以使用 C 的 malloc(您的问题标记为 c)隐式为您的进程分配内存,但显式映射文件字节。
一个进程包含一个或多个线程,这些线程实际执行进程中的代码(从技术上讲,进程不运行,线程运行)并用内核线程对象表示。
根据here进行的一些测试,具有2GB默认地址空间的32位Windows XP系统可以创建大约2025个线程:
但是,在分配了 4GB 地址空间的 64 位 Windows XP 上运行的 32 位测试限制 创建了接近 3204 个线程:
但是,确切的线程和进程限制是非常可变的,这取决于很多因素。线程指定其堆栈大小的方式、进程指定其最小工作集的方式、可用物理内存量和系统提交限制的方式。在任何情况下,您通常不必在现代系统上担心这一点,因为如果您的应用程序真的超过线程限制,您应该重新考虑您的设计,因为几乎总是有替代方法来完成相同的目标,数量合理。
【讨论】:
是的,在 32 位系统上每个进程的虚拟地址空间为 4GB(232 字节)。实际上,实际使用的少量虚拟内存对应于处理器缓存、物理内存或磁盘(或计算机决定放置内容的其他位置)中的位置。
理论上(这种行为在常见操作系统中非常普遍),如果操作系统决定将物理内存中无法容纳的所有内容放到磁盘上,进程实际上可以使用其所有虚拟内存,但这会使该程序非常慢,因为每次它试图访问一些未缓存的内存位置时,它都必须从磁盘中获取它。
您问您提供的图片是否可以增长到 4GB。其实你给的图片已经占满了4GB。这是一种将进程的 4GB 虚拟内存划分为不同部分的方法。此外,如果您正在考虑堆和堆栈“增长”,它们并没有真正增长。他们在该分区布局中为他们分配了一定数量的内存,并且他们只是根据需要使用该内存(堆栈移动指针,堆维护已使用和未使用内存的数据结构等)。
【讨论】:
你读过维基百科的virtual memory、process、address space 页面吗?
你读过什么关于advanced unix programming的书?或advanced linux programming?
通常,地址空间是一组有效的段(图中不是蓝色的)。
尝试(在 Linux 系统上)
cat /proc/self/maps
和
cat /proc/$$/maps
多了解一点。
另见this question 和this。阅读Operating Systems: Three Easy Pieces
当然,内核可以设置一些限制(另见setrlimit(2) syscall)。它们是资源限制(交换空间、RAM 等)。
【讨论】:
回答被忽略的部分...
可以有多少进程是有限制的。内核保留在其虚拟地址空间部分(这是共享的,否则您将无法在每个进程中访问内核)中的所有每个进程的数据结构都会占用一些空间。因此,例如,如果有 1GB 可用于此数据并且内核中每个进程只需要一个 4KB 页面,那么您最多可以得到大约 250,000 个进程。在实践中,这个数字通常要小得多,因为事情更复杂,并且为每个进程的各种事情保留了物理内存。例如,请参阅Mark Russinovich's article on process and thread limits in Windows 了解更多详情。
【讨论】: