编程上下文中的虚拟地址空间

Posted

技术标签:

【中文标题】编程上下文中的虚拟地址空间【英文标题】:Virtual address space in the context of programming 【发布时间】:2012-03-19 16:45:16 【问题描述】:

我对虚拟地址空间的含义感到困惑。在 32 位机器中,一个进程可以寻址 2^32 个内存位置。这是否意味着每个进程的虚拟地址空间是 2^32 (4GB) ?

下面是一个进程的虚拟地址空间的快照。这可以增长到4GB吗?这样的系统中的进程数有限制吗?

【问题讨论】:

【参考方案1】:

这可以增长到 4GB 吗?

地址空间的大小受唯一指针值的数量限制。对于 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 个线程:

但是,确切的线程和进程限制是非常可变的,这取决于很多因素。线程指定其堆栈大小的方式、进程指定其最小工作集的方式、可用物理内存量和系统提交限制的方式。在任何情况下,您通常不必在现代系统上担心这一点,因为如果您的应用程序真的超过线程限制,您应该重新考虑您的设计,因为几乎总是有替代方法来完成相同的目标,数量合理。

【讨论】:

Vista 64 上的 32 位应用程序 - 我目前的记录,一个应用程序中有 4000 个线程,(总共超过 5000 个),没问题,(最大堆栈大小设置为 128K)。 只是为了好玩,我将堆栈设置为 65536,可以在一个应用程序上创建 5000 个线程。尝试 6000 导致“线程创建错误”异常框 :(. 有人计算非 Windows NT 机器上的最大线程数吗?我在任何地方都找不到这方面的任何信息。【参考方案2】:

是的,在 32 位系统上每个进程的虚拟地址空间为 4GB(232 字节)。实际上,实际使用的少量虚拟内存对应于处理器缓存、物理内存或磁盘(或计算机决定放置内容的其他位置)中的位置。

理论上(这种行为在常见操作系统中非常普遍),如果操作系统决定将物理内存中无法容纳的所有内容放到磁盘上,进程实际上可以使用其所有虚拟内存,但这会使该程序非常慢,因为每次它试图访问一些未缓存的内存位置时,它都必须从磁盘中获取它。

您问您提供的图片是否可以增长到 4GB。其实你给的图片已经占满了4GB。这是一种将进程的 4GB 虚拟内存划分为不同部分的方法。此外,如果您正在考虑堆和堆栈“增长”,它们并没有真正增长。他们在该分区布局中为他们分配了一定数量的内存,并且他们只是根据需要使用该内存(堆栈移动指针,堆维护已使用和未使用内存的数据结构等)。

【讨论】:

“如果操作系统决定将它无法放入物理内存的所有内容都放到磁盘上”...请原谅我,但这并不是所有现代桌面/服务器操作系统所做的(Windows ,OS X,Linux,BSD)? (也就是说,除非您专门禁用该功能。) @DietrichEpp 是的,但强调一切,我不想说什么是确定的,什么时候计算机真的可以做它想做的事。跨度> 除了把它放在磁盘上之外,它还能对那些不适合内存的数据做什么? (假设它还没有在磁盘上。) @DietrichEpp 它可能会停止尝试并给你一个内存分配错误。 Linux 不这样做。如果你要求的内存比你拥有的多,它会杀死一个进程来为你获取它,但它不会返回错误。【参考方案3】:

你读过***的virtual memory、process、address space 页面吗?

你读过什么关于advanced unix programming的书?或advanced linux programming?

通常,地址空间是一组有效的段(图中不是蓝色的)。

另请参阅 mmap(2) 和 execve(2) 页面。

尝试(在 Linux 系统上)

cat /proc/self/maps

cat /proc/$$/maps

多了解一点。

另见this question 和this。阅读Operating Systems: Three Easy Pieces

当然,内核可以设置一些限制(另见setrlimit(2) syscall)。它们是资源限制(交换空间、RAM 等)。

【讨论】:

【参考方案4】:

回答被忽略的部分...

可以有多少进程是有限制的。内核保留在其虚拟地址空间部分(这是共享的,否则您将无法在每个进程中访问内核)中的所有每个进程的数据结构都会占用一些空间。因此,例如,如果有 1GB 可用于此数据并且内核中每个进程只需要一个 4KB 页面,那么您最多可以得到大约 250,000 个进程。在实践中,这个数字通常要小得多,因为事情更复杂,并且为每个进程的各种事情保留了物理内存。例如,请参阅Mark Russinovich's article on process and thread limits in Windows 了解更多详情。

【讨论】:

这是共享的,否则你将无法在每个进程中访问内核:我不明白你的意思它是共享的乙>。谁共享什么? 例如,如果 there 的 1GB 可用于 this 数据:在哪里?哪些数据? @ptr_user7813604 内核的虚拟地址空间部分是共享的。它存在于每个进程的虚拟地址空间中。此部分的大小有限(4 GB 中的 1 或 2 GB)。因此,例如,如果您使用 4KB 内存页来描述每个进程状态,而您只有 1GB 的内核部分的 VAS,则最多 250K 进程。

以上是关于编程上下文中的虚拟地址空间的主要内容,如果未能解决你的问题,请参考以下文章

在Windows内核地址空间中将虚拟地址转换为物理地址

2018-2019-1 20165319 《信息安全系统设计基础》第八周学习总结

线程与进程

学习系统编程No.5虚拟地址空间

Linux进程地址空间与虚拟内存

2018-2019-1 20165325 《信息安全系统设计基础》第八周学习总结