3

我想使用 mmap 函数将文件映射到内存中,并想知道当前平台上的虚拟内存量是否足以映射一个巨大的文件。对于 32 系统,我无法映射大于 4 Gb 的文件。会给我可寻址内存的数量还是我应该测试的任何其他类型(off_t 或其他)
std::numeric_limits<size_t>::max()

正如 Lie Ryan 在他的评论中指出的那样,这里的“虚拟记忆”被滥用了。然而,问题仍然存在:有一个类型与指针相关联,它的最大值定义了您可以在系统上处理的内容的上限。这是什么类型?是 size_t 还是 ptrdiff_t?

4

5 回答 5

1

嗨,如果您在 win32 中编码,您可以使用 GlobalMemoryStatusEx 和 VirtualQueryEx

于 2010-11-18T13:19:30.473 回答
1

size_t只需要足够大以存储最大可能的单个连续对象。这可能与地址空间的大小不同(例如,在具有分段内存模型的系统上)

但是,在具有平坦内存空间的普通平台上,两者是相等的,因此size_t如果您知道目标 CPU,则可以在实践中使用。

无论如何,这并没有真正告诉你任何有用的东西。当然,32 位 CPU 有 4GB 内存空间,size_t32 位无符号整数也是如此。但这并没有说明您可以分配多少。操作系统使用了部分内存空间。您自己的应用程序已经使用了某些部分:用于将可执行文件映射到内存(以及它可能使用的任何动态库)、每个线程的堆栈、在堆上分配的内存等等。

所以不,诸如获取大小之类的技巧会size_t告诉您一些有关您正在运行的地址空间的信息,但没有什么非常有用的。您可以询问操作系统您的进程和其他指标使用了多少内存,但同样,这对您没有多大帮助。一个进程可能只使用几兆字节,但是如果将其分布在如此多的小分配上,以至于不可能找到大于 100MB 的连续内存块。因此,在 32 位机器上,进程几乎不使用内存,您不太可能进行这样的分配。(即使操作系统有一个神奇的WhatIsTheLargestPossibleMemoryAllocationICanMake()API,它仍然对你没有帮助。它会告诉你刚才开始你需要什么. 您无法保证在您尝试映射文件时答案仍然有效。

所以真的,你能做的最好的就是尝试映射文件,看看它是否失败。

于 2010-11-18T13:53:27.827 回答
1

问题是,指针的大小并不能告诉您实际上有多少“地址空间”可供您使用,即可以映射为单个连续块。

它受以下限制:

  • 操作系统。它可能会选择只为您提供理论上可能的地址范围的子集,因为操作系统自己的目的需要可映射内存(例如,使显卡帧缓冲区可见,当然也供操作系统本身使用)。
  • 可配置的限制。在 Linux / UNIX 上,分别使用“ulimit”命令。setrlimit() 系统调用允许以各种方式限制应用程序地址空间的最大大小,Windows 通过注册表参数也有类似的选项。
  • 应用程序的历史。如果应用程序广泛使用内存映射,则地址空间可以分段限制“可用”连续虚拟地址的最大大小。
  • 硬件平台。一些 CPU 的地址空间带有“空洞”;一个例子是 64 位 x86,其中指针只有在 0x0..0x7fffffffffff 或 0xffff000000000000 和 0xffffffffffffffff 之间才有效。即你有 2x128TB 而不是完整的 16EB。将其视为 48 位“有符号”指针...

最后,不要混淆“可用内存”和“可用地址空间”。执行 malloc(someBigSize) 和 mmap(..., someBigSize, ...) 之间存在区别,因为前者可能需要可用的物理内存来容纳请求,而后者通常只需要可用的足够大的空闲地址范围。

对于 UNIX 平台,部分答案是使用 getrlimit(RLIMIT_AS) ,因为它为应用程序的当前调用提供了上限 - 如上所述,用户和/或管理员可以配置它。您可以保证任何尝试映射大于该范围的区域都会失败。

于 2010-11-18T16:22:11.167 回答
1

关于您改写的问题“您可以在系统上解决的问题的上限”,这有点误导;它是特定于硬件架构的。有 64 位架构 (x64, sparc),其 MMU 很高兴允许 (uintptr_t)(-1) 作为有效地址,即您可以将某些内容映射到 64 位地址空间的最后一页。操作系统是否允许应用程序这样做又是一个完全不同的问题......

对于用户应用程序,“高分”并不(总是)先验固定。它可以在例如 Solaris 或 Linux 上进行调整。这就是 getrlimit(RLIMIT_AS) 的用武之地。

请注意,根据规范,没有什么可以阻止(奇怪的)操作系统设计选择例如将应用程序堆栈和堆放在“低”地址,而将代码放在“高”地址,在具有地址空间漏洞的平台上. 您需要完整的 64 位指针,不能让它们变得更小,但可能存在任意数量的“不可访问/无效”范围,这些范围永远不会提供给您的应用程序。

于 2010-11-18T16:30:08.397 回答
0

你可以试试sizeof(int*)。这将为您提供目标平台上指针的长度(以字节为单位)。因此,您可以找出可寻址空间有多大。

于 2010-11-18T13:18:05.453 回答