如何管理大型数组

时间:2012-04-20 11:21:11

标签: c++ optimization memory-management

我有一个c ++程序,它使用了几个非常大的双精度数组,我想减少这个程序特定部分的内存占用。目前,我正在分配其中的100个,每个可以达到100 Mb。

现在,我确实有这样的优势,最终这些数组的一部分在程序执行的后期部分变得过时了,并且几乎不需要在任何时候将任何一个数组都存储在内存中。 / p>

我的问题是:

在使用new或malloc创建数组之后是否有任何告诉操作系统的方法是不再需要它的一部分? 我得出的结论是,实现这一目标的唯一方法是声明一个指针数组,每个指针指向一个块,表示所需数组的1Mb,这样就不再需要旧的块了。可以重用于数组的新位。在我看来,这就像编写一个看起来像一个大锤的定制内存管理器一样,这也会造成一点性能损失

我无法移动数组中的数据,因为它会导致太多的线程争用问题。尽管只有一个线程可以写入任何给定的数组,但是任何时候都可以通过大量线程中的任何一个访问这些数组。

5 个答案:

答案 0 :(得分:4)

这取决于操作系统。 POSIX(包括Linux)具有系统调用madvise以提高内存性能。从手册页:

  

madvise()系统调用建议内核如何处理从地址addr开始并具有大小长度字节的地址范围中的分页输入/输出。它允许应用程序告诉内核它希望如何使用某些映射或共享内存区域,以便内核可以选择适当的预读和缓存技术。此调用不会影响应用程序的语义(MADV_DONTNEED除外),但可能会影响其性能。内核可以自由地忽略这些建议。

有关详细信息,请参阅madvise的手册页。

编辑:显然,上述说明不够明确。所以,这里有一些更多的细节,其中一些是针对Linux的。

您可以使用mmap分配一块内存(直接来自操作系统而不是libc),这些内存不受任何文件的支持。对于大块内存,malloc正在执行完全相同的操作。您必须使用munmap来释放内存 - 无论madvise的使用情况如何:

void* data = ::mmap(nullptr, size, PROT_READ | PROT_WRITE,
    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
// ...
::munmap(data, size);

如果你想摆脱这个块的某些部分,可以使用madvise告诉内核这样做:

madvise(static_cast<unsigned char*>(data) + 7 * page_size,
    3 * page_size, MADV_DONTNEED);

地址范围仍然有效,但不再支持 - 无论是物理RAM还是存储。如果稍后访问这些页面,内核将动态分配一些新页面并将它们重新初始化为零。请注意, dontneed 页面也是进程虚拟内存大小的一部分。可能有必要对虚拟内存管理进行一些配置更改,例如,激活过度提交。

答案 1 :(得分:1)

如果我们有更多细节,那么回答会更容易。

1°)问题的答案“在使用new或malloc创建数组之后是否有任何告诉操作系统的方法,不再需要其中的一部分?”是“不是真的”。这就是C和C ++以及任何允许您手动处理内存的语言。

2°)如果您使用的是C ++而不是C,则不应使用malloc。

3°)也不是阵列,除非有非常特殊的原因。使用std :: vector。

4°)优选地,如果您需要经常更改阵列的内容并减少内存占用,请使用链接列表(std :: list),尽管单独“访问”内容会更加昂贵列表(但如果你只是迭代它,几乎同样快)。

答案 2 :(得分:1)

指向std::deque的{​​{1}}可以完成这项工作,但你最好使用deque创建一个专用容器,这样你就可以重新映射索引,最重要的是,定义何时不再使用条目

专用容器还可以包含读/写锁,因此可以以线程安全的方式使用。

答案 3 :(得分:0)

您可以尝试使用列表而不是数组。当然list比数组“重”但另一方面很容易重建一个列表,这样当它变得过时时你可以扔掉它的一部分。您还可以使用一个包装器,它只包含索引,说明列表的哪个部分是最新的,哪个部分可以重复使用。 这将有助于您提高性能,但需要更多(可重用)内存。

答案 4 :(得分:0)

按块分配delete[] - 和new[] - 在路上似乎是一个很好的解决方案。可以尽可能少地执行内存管理。不要自己重用块,只需取消分配旧块并在需要时分配新块。