是否可以在POSIX系统上部分释放动态分配的内存?

时间:2015-09-16 19:06:01

标签: c++ memory memory-management posix

我有一个C ++应用程序,我有时需要一个POD类型的大缓冲区(例如25个 b illion float s的数组)在一个连续的内存中同时保存块。这个特定的内存组织是由应用程序使用一些对数据进行操作的C API这一事实驱动的。因此,不同的安排(例如std::deque使用的较小内存块列表)是不可行的。

应用程序有一个以流式方式在阵列上运行的算法;想想这样的事情:

std::vector<float> buf(<very_large_size>);
for (size_t i = 0; i < buf.size(); ++i) do_algorithm(buf[i]);

此特定算法是已应用于数据集的早期处理步骤的流水线的结论。因此,一旦我的算法通过了数组中的i元素,应用程序就不再需要它了。

因此,理论上,我可以释放内存,以便在浏览数据时减少应用程序的内存占用。但是,执行类似于realloc()(或std::vector<T>::shrink_to_fit())的操作会效率低下,因为我的应用程序必须花费时间在重新分配时将未使用的数据复制到新的位置。

我的应用程序在兼容POSIX的操作系统(例如Linux,OS X)上运行。是否有任何接口可以让操作系统从内存块的前面仅释放指定的区域?这似乎是最有效的方法,因为我可以通知内存管理器,例如,一旦我完成了内存块的前2 GB就可以回收。

4 个答案:

答案 0 :(得分:5)

如果你的整个缓冲区必须同时存在于内存中,那么你可能不会在以后稍微释放它时获得太多收益。

这篇文章的要点基本上是不要告诉你做你想做的事情,因为如果实际上并不需要,操作系统不会不必要地将你的应用程序的内存保存在RAM中。这是&#34;常驻内存使用与#34;之间的差异。和&#34;虚拟内存使用&#34;。 &#34;生化&#34;是目前使用的和在RAM中,&#34;虚拟&#34;是应用程序的总内存使用量。只要您的交换分区足够大,&#34;虚拟&#34;记忆几乎不是问题。 [我假设您的系统不会耗尽虚拟内存空间,这在64位应用程序中是正确的,只要您没有使用数百TB的虚拟空间!]

如果您仍然想要这样做,并希望有一些合理的可移植性,我建议建立一个&#34;包装器&#34;它的行为类似于std::vector,并且一次分配一些兆字节(或者几千兆字节)的内存,然后是:

 for (size_t i = 0; i < buf.size(); ++i) {
    do_algorithm(buf[i]);
    buf.done(i);
 }

done方法只会检查i的值是否(超过当前缓冲区末尾的一个元素)并释放它。 [这应该很好地内联,并且在平均循环上产生非常小的开销 - 假设元素实际上按线性顺序使用]。

除非do_algorithm(buf[i])花费相当长的时间(当然很多秒,可能是几分钟甚至几小时),否则我会非常惊讶。当然,如果你真的对这个记忆有其他有用的东西,它只能提供帮助。即使这样,如果系统内存不足,操作系统也会通过将其交换到磁盘来回收未被主动使用的内存。

换句话说,如果你分配100GB,填充它,让它保持不动,它最终将全部放在硬盘而不是RAM中。

此外,应用程序中的堆保留释放的内存并且操作系统在应用程序退出之前不会恢复内存并且当然,如果仅释放更大分配的一部分,那么,这并不奇怪。运行时不会释放它,直到整个块被释放。因此,正如开头所述,我不确定这对您的申请有多大帮助。

关于&#34;调整&#34;和&#34;性能改进&#34;,您需要衡量和比较基准,并看看它有多大帮助。

答案 1 :(得分:4)

  

是否可以在POSIX系统上部分释放动态分配的内存?

您无法使用malloc() / realloc() / free()执行此操作。

但是,您可以使用mmap()munmap()以便携式方式执行此操作。关键点在于,如果您munmap()某个页面,malloc()以后可以使用该页面:

  • 使用mmap();
  • 创建匿名映射
  • 随后致电munmap()了解您不再需要的地区。

可移植性问题是:

  • POSIX没有指定匿名映射。某些系统提供MAP_ANONYMOUSMAP_ANON标记。其他系统提供可以为此目的映射的特殊设备文件。 Linux提供了两者。
  • 我不认为POSIX保证当您munmap()页面时,malloc()将能够使用它。但我认为它将使用mmap() / unmap()的所有系统。

<强>更新

如果您的内存区域太大,以至于肯定会将大多数页面写入交换,则不会使用文件映射而不是匿名映射来丢失任何内容。文件映射在POSIX中指定。

答案 2 :(得分:2)

如果你没有方便的std::vector(在这种情况下不会给你太多,因为你永远不想复制/ return /移动那个野兽),你可以做你自己的记忆处理。向操作系统询问整个内存页面(通过mmap)并根据需要返回它们(使用munmap)。您可以通过其第一个参数和可选的mmap标志告诉MAP_FIXED以将页面映射到特定地址(当然,您必须确保该页面不被占用),这样您就可以构建一个区域连续记忆。如果您预先分配整个内存,那么这不是问题,您可以使用单个mmap来执行此操作,并让操作系统选择一个方便的位置来映射它。最后,这是malloc内部的作用。对于没有sys/mman.h的平台,如果您能够接受这样的事实,即在早期就不会返回内存,那么使用malloc并不困难。

我怀疑如果您的分配大小始终是页面大小的倍数,realloc将足够聪明,不会复制任何数据。不过,您必须尝试这一点,看看它是否有效(或参考您的malloc文档)。

答案 3 :(得分:0)

mremap可能正是您需要的。只要您要移动整个页面,就可以进行超快速的重新分配(实际上内核会为您完成)。