Jas*_*n R 9 c++ memory posix memory-management
我有一个C++应用程序,我有时需要一个POD类型的大缓冲区(例如一个25 b illion floats 的数组)在一个连续的块中同时保存在内存中.这个特定的内存组织是由应用程序使用一些对数据进行操作的C API这一事实驱动的.因此,不同的安排(例如像std::deque使用的较小的存储器块的列表)是不可行的.
该应用程序有一个以流式方式在阵列上运行的算法; 想想这样的事情:
std::vector<float> buf(<very_large_size>);
for (size_t i = 0; i < buf.size(); ++i) do_algorithm(buf[i]);
Run Code Online (Sandbox Code Playgroud)
该特定算法是已应用于数据集的早期处理步骤的流水线的结论.因此,一旦我的算法通过了i数组中的-th元素,应用程序就不再需要它了.
因此,从理论上讲,我可以释放内存,以便在浏览数据时减少应用程序的内存占用.但是,做类似于realloc()(或a std::vector<T>::shrink_to_fit())的操作会效率低下,因为我的应用程序必须花费时间在重新分配时将未使用的数据复制到新的位置.
我的应用程序在兼容POSIX的操作系统(例如Linux,OS X)上运行.是否有任何接口可以让操作系统从内存块的前面仅释放指定的区域?这似乎是最有效的方法,因为我可以通知内存管理器,例如,一旦我完成了内存块的前2 GB就可以被回收.
如果你的整个缓冲区必须同时在内存中,那么你可能不会从以后稍后释放它中获得太多收益.
这篇文章的要点基本上是不要告诉你做你想做的事情,因为如果实际上并不需要,操作系统不会不必要地将应用程序的内存保存在RAM中.这是"驻留内存使用"和"虚拟内存使用"之间的区别."Resident"是当前使用的,在RAM中,"virtual"是应用程序的总内存使用量.只要您的交换分区足够大,"虚拟"内存几乎不是问题.[我假设您的系统不会耗尽虚拟内存空间,这在64位应用程序中是正确的,只要您没有使用数百TB的虚拟空间!]
如果你仍然想这样做,并希望有一些合理的可移植性,我建议建立一个行为类似的"包装器",std::vector并一次分配几兆字节(或几千兆字节)的内存块,然后像:
for (size_t i = 0; i < buf.size(); ++i) {
do_algorithm(buf[i]);
buf.done(i);
}
Run Code Online (Sandbox Code Playgroud)
该done方法将简单地检查值if是否i是(一个元素)超过当前缓冲区的末尾,并释放它.[这应该很好地内联,并且在平均循环上产生非常小的开销 - 假设元素实际上以线性顺序使用,当然].
如果你能获得任何东西,我会非常惊讶,除非do_algorithm(buf[i])需要相当长的时间(当然很多秒,可能是几分钟甚至几小时).当然,如果你真的对这个记忆有其他有用的东西,它只会有所帮助.即使这样,如果系统内存不足,操作系统也会通过将其交换到磁盘来回收未被主动使用的内存.
换句话说,如果你分配100GB,填充它,让它保持不动,它最终将全部放在硬盘而不是RAM中.
此外,应用程序中的堆保留释放的内存并且操作系统在应用程序退出之前不会获取内存并且完全没有异常 - 当然,如果只释放更大分配的部分,则运行时将不会释放它直到整个块被释放.因此,正如开头所述,我不确定这对您的应用程序有多大帮助.
与关于"调整"和"性能改进"的所有内容一样,您需要测量和比较基准测试,并了解它有多大帮助.
是否可以在 POSIX 系统上部分释放动态分配的内存?
您不能使用malloc()//realloc()来做到这一点free()。
mmap()但是,您可以使用和以半便携式方式完成此操作munmap()。关键点是,如果你munmap()有某个页面,malloc()以后可以使用该页面:
mmap()使用;创建匿名映射munmap()您不再需要的区域。可移植性问题是:
MAP_ANONYMOUS或MAP_ANON标记。其他系统提供可以为此目的进行映射的特殊设备文件。Linux 两者都提供。munmap()一个页面时,malloc()就能使用它。但我认为它适用于所有具有mmap()/的系统unmap()。更新
如果您的内存区域太大,大多数页面肯定会被写入交换,那么通过使用文件映射而不是匿名映射,您不会丢失任何东西。文件映射在 POSIX 中指定。