提问人:KPexEA 提问时间:10/8/2008 最后编辑:soulmergeKPexEA 更新时间:5/17/2016 访问量:26872
你能在 c 或 c++ 中分配一个非常大的单个内存块(> 4GB)吗?
Can you allocate a very large single chunk of memory ( > 4GB ) in c or c++?
问:
这些天来,由于内存量非常大,我想知道是否可以分配大于 4GB 的单个内存块?或者我是否需要分配一堆较小的块并处理它们之间的切换?
为什么??? 我正在处理一些openstreetmap xml数据,这些文件很大。我目前正在流式传输它们,因为我无法将它们全部加载到一个块中,但我只是对 malloc 或 new 的上限感到好奇。
答:
这取决于你使用的是哪个 C 编译器,以及什么平台(当然),但你不能分配最大的连续可用内存块(可能比你需要的要少)没有根本原因。当然,您可能必须使用 64 位系统来解决比 RAM 更多的问题......
有关历史和详细信息,请参阅 Malloc
在 alloc.h 中调用 HeapMax 以获取最大可用块大小
简短的回答:不太可能
为此,您绝对必须使用 64 位处理器。 其次,它将取决于操作系统对为单个进程分配超过 4G RAM 的支持。
从理论上讲,这是可能的,但您必须阅读内存分配器的文档。您也更容易出现内存碎片问题。
有关于 Windows 内存管理的良好信息。
评论
您是否考虑过使用内存映射文件?由于您正在加载非常大的文件,因此这似乎是最好的方法。
对于 64 位操作系统(以及具有如此多内存的机器)来说,这应该不是问题。
如果 malloc 无法应对,那么操作系统肯定会提供允许您直接分配内存的 API。在 Windows 下,可以使用 VirtualAlloc API。
这取决于操作系统是否会为您提供允许对 4GB 以上的内存进行寻址的虚拟地址空间,以及编译器是否支持使用 new/malloc 分配内存。
对于 32 位 Windows,您将无法获得大于 4GB 的单个块,因为指针大小为 32 位,因此将虚拟地址空间限制为 4GB。(您可以使用物理地址扩展来获得超过 4GB 的内存;但是,我相信您必须自己将该内存映射到 4GB 的虚拟地址空间中)
对于 64 位 Windows,VC++ 编译器支持 64 位指针,虚拟地址空间的理论限制为 8TB。
我怀疑这同样适用于 Linux/gcc - 32 位不允许你,而 64 位允许你。
评论
内存映射文件的优点是,您可以打开一个比 4Gb 大得多的文件(在 NTFS 上几乎是无限的!),并且有多个 <4Gb 内存窗口进入其中。
它比打开文件并将其读取到内存中要高效得多,在大多数操作系统上,它使用内置的分页支持。
评论
物理和虚拟内存布局入门
您将需要 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) 个唯一地址的连续数据结构。这允许构建和管理更大的连续数据结构。
评论
就像其他人说的那样,购买一台 64 位机器是必经之路。但即使在 32 位计算机英特尔计算机上,如果您的操作系统和 CPU 支持 PAE,您也可以处理大于 4GB 的内存区域。不幸的是,32 位 WinXP 不这样做(32 位 Vista 吗?Linux 默认允许你这样做,但你将被限制在 4gb 区域,即使使用 mmap() 也是如此,因为指针仍然是 32 位。
但是,您应该做的是让操作系统为您处理内存管理。进入一个可以处理这么多 RAM 的环境,然后将 XML 文件读入 (a) 数据结构,并让它为您分配空间。然后对内存中的数据结构进行操作,而不是对 XML 文件本身进行操作。
然而,即使在 64 位系统中,你也无法控制程序的哪些部分实际上位于 RAM、缓存中或分页到磁盘中,至少在大多数情况下,因为操作系统和 MMU 自己处理这个问题。
正如 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如果系统上的 size_t 大于 32 位,则您已经清除了第一个障碍。但是 C 和 C++ 标准不负责确定对 new 或 malloc 的任何特定调用是否成功(大小为 0 的 malloc 除外)。这完全取决于操作系统和堆的当前状态。
评论