你能在 c 或 c++ 中分配一个非常大的单个内存块(> 4GB)吗?

Can you allocate a very large single chunk of memory ( > 4GB ) in c or c++?

提问人:KPexEA 提问时间:10/8/2008 最后编辑:soulmergeKPexEA 更新时间:5/17/2016 访问量:26872

问:

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

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

C++ C 内存 malloc

评论

0赞 epochwolf 10/8/2008
有人可能想知道为什么你需要这样做。:)
8赞 shoosh 10/8/2008
考虑这样做的必要性并不难。
0赞 Serafina Brocious 10/8/2008
物理内存仿真是我首先想到的......
1赞 Roger Nelson 12/25/2008
这就是为什么XML不应该用于数据存储,尤其是不能用作数据库的原因。它最初被设计为一种数据传输机制。
0赞 ApplePieIsGood 4/27/2009
听起来像是数据传输给我。但同意,XML可能被过度使用,如果你是这个意思的话。

答:

12赞 Steven A. Lowe 10/8/2008 #1

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

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

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

27赞 Benoit 10/8/2008 #2

简短的回答:不太可能

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

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

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

评论

6赞 Martin Beckett 6/2/2009
32 位 Intel 处理器实际上具有 36Gb 内存的 64 位地址 - 只是桌面版 Windows 的许可证将您限制为 4Gb。Linux/BSD 可以在 32 位 CPU 上访问 64Gb。
5赞 Marco van de Voort 6/10/2009
即便如此,Afaik您仍然被困在3GB的进程限制中。
4赞 R.. GitHub STOP HELPING ICE 9/8/2011
不,如果您有 64 位程序,则没有 3GB 的进程限制。它可以使用计算机支持的尽可能多的虚拟地址空间(大约 48-52 位,我忘记了确切的数字)和操作系统拥有的物理内存,并配置为允许该过程。
9赞 1800 INFORMATION 10/8/2008 #3

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

14赞 Rob Walker 10/8/2008 #4

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

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

6赞 Franci Penov 10/8/2008 #5

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

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

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

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

评论

0赞 Branan 10/9/2008
只是好奇,你从哪里得到 8TB?英特尔文档给出了 48 位的实际地址大小,即 256TB 的地址空间。
0赞 Franci Penov 10/9/2008
我不应该把它表述为“理论性的”。实际数字来自 Windows 版本的内存限制 - msdn.microsoft.com/en-us/library/aa366778(VS.85).aspx
22赞 Martin Beckett 10/8/2008 #6

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

评论

0赞 andy 10/8/2008
“几乎更高效”是什么意思?
0赞 Martin Beckett 10/8/2008
对不起,我改变了这句话,多了一个词。
1赞 QBziZ 10/8/2008
内存映射文件避免了将文件全部复制到已提交的内存中(可能大部分复制回分页文件),因为它仅使用原始文件作为已提交内存的后备存储。
2赞 Martin Beckett 11/22/2008
NTFS 上的最大文件大小为 2^64,这不是无限的,但足够接近,可以四处喝酒!
0赞 1800 INFORMATION 3/25/2009
NTFS 中的最大文件大小远小于实际 mgb。en.wikipedia.org/wiki/NTFS。理论值:16 EiB 减去 1 KiB(264 − 210 字节)。实现:16 TiB 减去 64 KiB(244 − 216 字节)
24赞 ConcernedOfTunbridgeWells 10/10/2008 #7

物理和虚拟内存布局入门

您将需要 64 位 CPU 和 O/S 构建,并且几乎可以肯定有足够的内存来避免破坏您的工作集。一些背景:

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

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

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

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

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

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

评论

2赞 Kibbee 2/22/2009
或者你可以选择简单的AMD Phenom或Intel Quadcore。我最近组装了一台具有 8 GB 内存和 4x500GB 硬盘的四核机器,价格刚刚超过 1000 加元。只要您将视频卡排除在画面之外,您就可以以便宜的价格获得大量功能。
2赞 Zachary Hamm 2/26/2009 #8

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

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

然而,即使在 64 位系统中,你也无法控制程序的哪些部分实际上位于 RAM、缓存中或分页到磁盘中,至少在大多数情况下,因为操作系统和 MMU 自己处理这个问题。

4赞 RandomNickName42 6/2/2009 #9

正如 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 的初始页面大小,随后奔腾增加了 4MB。如今,AMD64(AMD 系列 10h 处理器软件优化指南)的最大页表条目大小为 1GB。这意味着对于您的情况,假设您刚刚做了 4GB,它只需要内核目录中的 4 个唯一条目来定位/分配和许可进程的内存。

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

内容介绍。4 关于内存管理器 4 虚拟地址空间。5 内核虚拟的动态分配 地址空间。5 x86 体系结构的详细信息。6 64 位体系结构的详细信息。7 x86 中的内核模式堆栈跳转 架构。7 使用多余的池内存。8 安全性:地址空间布局 随机化。9 ASLR对图像加载的影响 地址。ASLR 的 9 个好处。11 如何创建基于动态的 图像。11 I/O 带宽。11 Microsoft SuperFetch。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

3赞 Dan Olson 6/2/2009 #10

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