43

这些天我想知道有非常大量的内存,是否可以分配一块大于 4GB 的内存?还是我需要分配一堆较小的块并处理它们之间的切换?

为什么???我正在处理一些openstreetmap xml数据,这些文件很大。我目前正在将它们流式传输,因为我无法将它们全部加载到一个块中,但我只是对 malloc 或 new 的上限感到好奇。

4

10 回答 10

27

简短回答:不太可能

为了使其工作,您绝对必须使用 64 位处理器。其次,它将取决于操作系统是否支持将超过 4G 的 RAM 分配给单个进程。

从理论上讲,这是可能的,但您必须阅读内存分配器的文档。您也更容易受到内存碎片问题的影响。

有关于Windows 内存管理的好信息。

于 2008-10-08T01:22:16.007 回答
24

物理和虚拟内存布局入门

您将需要 64 位 CPU 和操作系统构建以及几乎可以肯定有足够的内存来避免破坏您的工作集。一点背景:

32 位机器(总的来说)具有可以存储 2^32 (4,294,967,296) 个唯一值之一的寄存器。这意味着 32 位指针可以寻址 2^32 个唯一内存位置中的任何一个,这就是神奇的 4GB 限制的来源。

一些 32 位系统(例如 SPARCV8 或 Xeon)具有 MMU,它可以使用一个技巧来允许更多的物理内存。这允许多个进程占用总计超过 4GB 的内存,但每个进程仅限于其自己的 32 位虚拟地址空间。对于查看虚拟地址空间的单个进程,32 位指针只能映射 2^32 个不同的物理位置。

我不会详细介绍,但这个演示文稿(警告:powerpoint)描述了它是如何工作的。一些操作系统具有操作 MMU 并将不同的物理位置交换到用户级别控制下的虚拟地址空间的工具(例如此处描述的那些- 感谢上面的 FP)。

操作系统和内存映射的 I/O 将占用一些虚拟地址空间,因此并非所有 4GB 都必须对进程可用。例如,Windows 默认占用 2GB,但如果在启动时调用 /3G 开关,则可以设置为仅占用 1GB。这意味着此类 32 位架构上的单个进程只能在内存中构建一个小于 4GB 的连续数据结构。

这意味着您必须显式使用Windows 上的PAE工具或Linux 上的等效工具来手动交换覆盖。这不一定那么难,但需要一些时间才能开始工作。

或者,您可以获得具有大量内存的 64 位机器,这些问题或多或少会消失。至少在理论上,具有 64 位指针的 64 位架构可以构建具有多达 2^64 (18,446,744,073,709,551,616) 个唯一地址的连续数据结构。这允许构建和管理更大的连续数据结构。

于 2008-10-09T18:28:01.350 回答
22

内存映射文件的优点是您可以打开一个比 4Gb 大得多的文件(在 NTFS 上几乎是无限的!)并在其中有多个 <4Gb 的内存窗口。
它比打开文件并将其读入内存要有效得多,在大多数操作系统上它使用内置的分页支持。

于 2008-10-08T01:54:15.100 回答
14

对于 64 位操作系统(以及具有这么多内存的机器),这应该不是问题。

如果 malloc 无法应对,那么操作系统肯定会提供允许您直接分配内存的 API。在 Windows 下,您可以使用VirtualAlloc API。

于 2008-10-08T01:34:05.513 回答
12

这取决于您使用的是哪个 C 编译器,以及在哪个平台上(当然),但是没有根本原因为什么您不能分配最大的连续可用内存块 - 这可能比您需要的要少。当然,您可能必须使用 64 位系统来解决比 RAM 多的问题...

有关历史和详细信息,请参见Malloc

在 alloc.h 中调用HeapMax以获得最大的可用块大小

于 2008-10-08T01:20:08.600 回答
9

您是否考虑过使用内存映射文件?由于您正在加载非常大的文件,因此这似乎是最好的方法。

于 2008-10-08T01:32:46.720 回答
6

这取决于操作系统是否会为您提供允许寻址超过 4GB 的内存的虚拟地址空间,以及编译器是否支持使用 new/malloc 分配它。

对于 32 位 Windows,您将无法获得大于 4GB 的单个块,因为指针大小为 32 位,因此将您的虚拟地址空间限制为 4GB。(您可以使用物理地址扩展来获得超过 4GB 的内存;但是,我相信您必须自己将该内存映射到 4GB 的虚拟地址空间)

对于 64 位 Windows,VC++ 编译器支持 64 位指针,虚拟地址空间的理论限制为 8TB。

我怀疑这同样适用于 Linux/gcc - 32 位不允许你,而 64 位允许你。

于 2008-10-08T01:34:10.663 回答
4

正如 Rob 指出的那样,Windows 的 VirtualAlloc 是一个不错的选择,匿名文件映射也是如此。但是,特别是关于您的问题,“如果 C 或 C++”的答案可以分配,答案是否定的,即使在 WIN7 RC 64 上也不支持

在 exe 文件的 PE/COFF 规范中,指定 HEAP 保留和 HEAP 提交的字段是一个 32 位的数量。这符合 Windows CRT 中当前堆实现的物理大小限制,仅不足 4GB。因此,没有办法从 C/C++ 分配超过 4GB 的空间(从技术上讲,CreateFileMapping 和 VirtualAlloc/VirtualAllocNuma 等操作系统支持工具......不是 C 或 C++)。

此外,请注意存在称为页表的底层 x86 或 amd64 ABI 构造实际上会做你所关心的事情,为你更大的请求分配更小的块,即使这发生在内核内存中,也会对整个系统产生影响,这些表是有限的。

如果您在如此宏大的目的中分配内存,则建议您根据分配粒度(VirtualAlloc 强制执行)进行分配,并确定可选标志或方法以启用更大的页面。

4kb 页面是 386 的初始页面大小,随后 pentium 增加了 4MB。今天,AMD64(AMD 系列 10h 处理器的软件优化指南)的最大页表条目大小为 1GB。这意味着在这里你的情况,假设你刚刚做了 4GB,它只需要内核目录中的 4 个唯一条目来定位\分配和许可你的进程的内存。

Microsoft 还发布了这本手册,阐明了应用程序内存的一些更精细的点,并用于 Vista/2008 平台和更新的平台。

内容

介绍。4

关于内存管理器 4

虚拟地址空间。5

内核虚拟地址空间的动态分配。5

x86 架构的详细信息。6

64 位架构的详细信息。7

x86 架构中的内核模式堆栈跳跃。7

使用多余的池内存。8

安全性:地址空间布局随机化。9

ASLR 对图像加载地址的影响。9

ASLR 的好处.. 11

如何创建基于动态的图像。11

I/O 带宽。11

微软超取。12

页面文件写入。12

内存管理器和缓存管理器的协调 13

预取式聚类。14

大文件管理 15

休眠和待机。16

高级视频模型 16

NUMA 支持 17

资源分配。17

默认节点和亲和性。18

中断亲和。19

适用于应用程序的 NUMA 感知系统功能。19

驱动程序的 NUMA 感知系统功能。19

分页。20

可扩展性。20

效率和并行性.. 20

页帧号和 PFN 数据库。20

大页面。21

缓存对齐池分配。21

虚拟机。22

负载均衡。22

额外的优化。23

系统完整性。23

诊断硬件错误。23

代码完整性和驱动程序签名。24

错误检查期间的数据保存。24

你应该做什么。24

对于硬件制造商。24

对于驱动程序开发人员。24

对于应用程序开发人员。25

对于系统管理员。25

资源。25

于 2009-06-02T09:02:14.593 回答
3

如果 size_t 在您的系统上大于 32 位,那么您已经清除了第一个障碍。但是 C 和 C++ 标准不负责确定对 new 或 malloc 的任何特定调用是否成功(大小为 0 的 malloc 除外)。这完全取决于操作系统和堆的当前状态。

于 2009-06-02T09:24:53.863 回答
2

就像其他人所说的那样,获得 64 位机器是要走的路。但即使在 32 位机器上的英特尔机器上,如果您的操作系统和 CPU 支持PAE,您也可以处理大于 4gb 的内存区域。不幸的是,32 位 WinXP 不这样做(32 位 Vista 可以吗?)。Linux 默认允许您执行此操作,但您将被限制为 4gb 区域,即使使用 mmap(),因为指针仍然是 32 位的。

但是,您应该做的是让操作系统为您处理内存管理。进入一个可以处理那么多 RAM 的环境,然后将 XML 文件读入 (a) 数据结构,并让它为您分配空间。然后对内存中的数据结构进行操作,而不是对 XML 文件本身进行操作。

即使在 64 位系统中,您也不会对程序的哪些部分实际位于 RAM、缓存中或分页到磁盘有很多控制,至少在大多数情况下,因为操作系统和 MMU 处理这自己。

于 2009-02-25T21:44:18.367 回答