我正在尝试研究 d 维范围搜索算法的实用性,该算法在渐近情况下被证明是好的,但具有与之相关的大常数。这意味着我需要能够将 d 维空间中的点数改变为一些非常大的值。使用1<<20
(2 的 20 次方) 点开始导致 my malloc
s 返回空指针。我free
尽可能频繁地记忆,我在我能做的几个地方节省了我能做的很少的钱,但我希望能够提高到更接近1<<28
. 是否有处理这种大小的内存块的传统方法?
4 回答
如果您在 32 位处理器和/或操作系统上运行,或者正在为 32 位而不是 64 位编译,那么您不能,即使您在 64 位处理器上运行并为其编译,您也需要有很多物理内存 - malloc 尝试一个连续的块,所以交换文件对你没有好处。SIZE_MAX 将告诉您可以尝试分配的最大数量,但失败取决于物理限制。
你说分配这么大的块开始返回空指针。对我来说,这意味着它可以工作一段时间,随着时间的推移你会分配和释放其中的很多,并且在做了很多次之后,你开始得到空值。
如果是这种情况,您将看到一个典型的内存碎片案例。(如果我的假设不正确,请原谅下面的小说。)过去,我通过编写自己的内存管理器来处理此类问题,该管理器允许我重新定位内存中的对象以为分配新块腾出空间。如果您的代码必须能够将指针保存到分配的块中,那么您的内存管理器将不得不涉及一个指针实现,该实现将使移动变得透明。如果您依赖第三方软件,这将变得难以实现。
您可能会考虑为您将使用的每个块大小预先分配一个池。这确保了您永远不会以这样一种方式分割您的内存,即只有在您使用了整个大块池的情况下,一个大块才会不可用,而不是拥有大量可用内存,但仅限于小片段。检查一种称为Slab Allocation的方法。
我的可重定位内存实现是这样的:在程序执行开始时,我分配了最大的可用内存块。(mmap 是你的朋友。)如果我找不到可以满足分配请求的空闲片段,我会在它之前和之后找到一些具有大量空闲空间的块,并将其移动到前面的空闲空间的位置。我会计划这一举措,以便得到的空闲块足够大,可以用于新请求的分配。
这不是一个好的通用解决方案。它可能非常慢,我不会在需要实时性能的系统中使用它。(想一想,如果为了一次分配而必须对几十个块进行混洗会发生什么。最坏的情况是,为了满足一个请求,您必须复制每个分配的字节。)它还要求您可以容忍混洗每个指向此内存的指针。但如果绝对必要的话,它确实比slab分配器更有效地使用内存。
2^28 = 256MB。
如果您有足够的物理内存,肯定可以在 32 位或 64 位系统上使用。要检查您是否这样做,请获取的输出cat /proc/meminfo
并查找该MemFree
行。
我推荐的 API 是mmap()
(匿名映射)而不是malloc()
http://man7.org/linux/man-pages/man2/mmap.2.html
mmap
是一个系统调用,它直接向操作系统请求内存。这是malloc()
下面使用的东西。
如果malloc()
开始失败,那么您可能会遇到(稍微随意的)rlimit 限制。你应该能够稍微放松一下(见ulimit
)bash
;但请记住,设置这些限制是为了帮助保持系统在通用用途中的稳定性和可预测性。此外,请注意过度使用,这是操作系统可能会让您要求的内存超出其可能提供的内存,然后在您尝试使用它时杀死您。
如果您真的用完了地址空间并且您正在构建一个 32 位应用程序,那么请切换到 64 位。
如果您在 64 位应用程序中的地址空间不足,那么我建议您没有充分利用分配。需要填写大量数据,我希望您在地址空间用完之前用完时间。在这种情况下,您可能应该重新考虑使用空间的方式。
如果您确实需要比系统上可用的更大的地址空间,您可以根据需要创建一个文件(或多个文件)和mmap()
这些文件的片段。这允许操作系统尽其所能缓存文件,并且如果它确实耗尽了物理内存和交换(对于此类项目总是有风险),那么它可以在某个地方将数据分页到无需恐慌并杀死您的应用程序。
不幸的是,使用mmap()
这种方式确实需要您在该文件中管理自己的分配。