2012-04-20 41 views
3

我有一个使用几个非常大的双打数组的C++程序,我想减少程序的这个特定部分的内存占用量。目前,我正在分配其中的100个,每个可能是100 Mb。如何管理大型阵列

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

我的问题是这样的:

有没有告诉我OS创建新的或malloc的数组是它的一部分,不需要任何更多的后什么办法? 我得出的结论是,实现这一目标的唯一方法是声明一个指针数组,每个指针可以指向一个数据块,称为所需数组的1Mb,以便不需要的旧数据块更多可以重新用于阵列的新位。在我看来,像写一个自定义的内存管理器,看起来像是一个大锤,这将创建一个性能点击以及

我不能移动数组中的数据,因为它要走了导致太多的线程争用问题。数组可以随时被大量线程中的任何一个线程访问,尽管只有一个线程可以写入任何给定的数组。

+0

通常,对于非常大数组问题的答案是使用*稀疏数组* - 看起来像数组的数据结构,但实际上只存储相关元素。如果大部分数组都是空白的,这将起作用。这是真的吗?或者在某种程度上你是否真的需要给定数组中的所有元素? – 2012-04-20 11:25:52

+0

平台特定的解决方案是否可以接受? Posix允许你在一个大的区域进行'mmap',然后在你完成之后'munmap'部分的完成。 – 2012-04-20 11:26:33

回答

4

这取决于操作系统。包括Linux在内的POSIX系统调用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还是存储。如果稍后访问这些页面,内核将立即分配一些新页面并将它们重新初始化为零。请注意,不必页也是过程的虚拟内存大小的一部分。可能需要对虚拟内存管理进行一些配置更改,例如,激活过度提交。

+1

尽管如此,你不能“释放”或“删除”内存;这可能会尝试重新使用过程中不再可用的内存。 – 2012-04-20 11:34:23

+0

只需查看mmap的手册页即可。使用MAP_NORESERVE与MAP_ANONYMOUS或两者调用有什么好处? – camelccc 2012-04-20 15:32:29

+1

MAP_NORESERVE是关于内存过度提交,即初始内存分配是否成功,尽管可能会发生,但以后不能提供。如果您计划立即使用内存,则不应使用MAP_NORESERVE。 – nosid 2012-04-20 17:56:15

0

你可以尝试使用列表而不是数组。当然,列表比数组更重,但另一方面,重建列表很容易,以便在列表过时时可以丢弃其中的一部分。你也可以使用一个只包含索引的包装器,这些索引说明列表的哪一部分是最新的,哪一部分可以被重用。 这将有助于提高性能,但需要多一点(可重复使用)的内存。

+0

不必按顺序访问列表。遍历列表访问元素1000000+会很慢 – camelccc 2012-04-20 11:36:57

+0

如果一次只使用列表的一部分,这将不会很慢。实际上,这取决于列表的实施。 std中的列表非常优化,性能不会太慢​​。 – superM 2012-04-20 11:42:02

1

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

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

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

3°)阵列,除非是非常具体的原因。使用std :: vector。如果您需要经常更改数组的内容并减少内存占用,请使用链接列表(std :: list),但单独“访问”会更昂贵列表的内容(但是如果你只是遍历它,速度几乎一样快)。

1

A std::deque指针std::array<double,LARGE_NUMBER>可能会完成这项工作,但是您最好使用deque创建一个专用容器,以便您可以重新映射索引,最重要的是,定义何时不再使用条目。

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

0

分配块和delete[] -ing和new[]-在途中似乎是一个很好的解决方案。尽可能少地进行内存管理是可能的。不要重复使用块,只需解除旧块的分配并在需要时分配新块。