将大量二进制数据加载到RAM中

时间:2016-07-29 08:05:34

标签: c++ c++11 memory-management vector

我的应用程序需要从MegaBytes加载到几十千兆字节的二进制数据(多个文件)到RAM中。经过一番搜索,我决定使用std::vector<unsigned char>来达到这个目的,虽然我不确定它是最好的选择。

我会为每个文件使用一个向量。由于应用程序以前知道文件大小,因此会调用reserve()为其分配内存。有时候应用程序可能需要完全读取一个文件,而在其他一些文件中只需要部分文件和vector的迭代器就可以了。它可能需要从RAM中卸载文件并将其他文件放到适当位置,std::vector::swap()std::vector::shrink_to_fit()将非常有用。我不想在处理低级内存分配方面付出艰苦的努力(否则会与C一起使用)。

我有一些问题:

  • 应用程序必须从列表中加载更多文件到RAM中。怎么知道是否有足够的内存空间来加载一个文件?它应该拨打reserve()并查找错误吗?怎么样?仅当请求的大小大于reserve()时,引用仅说std::vector::max_size会引发异常。
  • std::vector<unsigned char>是否适用于将大量二进制数据存入RAM?我担心std::vector::max_size,因为它的参考说它的价值取决于系统或实施限制。我认为系统限制是免费RAM,是不是?所以,没问题。但是实现限制怎么样?是否存在任何可能妨碍我做我想做的实现?案例肯定,请给我一个替代方案。
  • 如果我想使用整个RAM空间,除了N GigaBytes,该怎么办?如果可以加载每个文件,是真正使用sysinfo()并基于可用RAM推断的最佳方法吗?

Obs。:应用程序的这一部分必须能够获得更高的性能(低处理时间/ CPU使用率和RAM消耗)。我很感激你的帮助。

2 个答案:

答案 0 :(得分:6)

  

如何知道是否有足够的内存空间来加载一个文件?

你不会事先知道。将加载过程包装在try-catch中。如果内存耗尽,则抛出std::bad_alloc(假设您使用默认分配器)。假设内存在加载代码中足够,并处理异常处理程序中缺少的内存。

  

但实施限制呢?   ...   是否存在任何可能妨碍我做我想做的实现?

您可以在运行时检查std::vector::max_size以进行验证。

如果程序是用64位字大小编译的,那么向量很可能有足够的max_size几百GB。

  

应用程序的这一部分必须获得更多性能

这与

冲突
  

我不想在处理低级别内存分配方面付出艰苦的努力

但是如果低级内存对于性能来说是值得的,那么你可以memory-map将文件放入内存。

  

我已经阅读了一些SO问题,以避免它们出现在需要高性能且更喜欢处理返回值的应用程序上,错误等等

不幸的是,如果您使用标准容器,则不能选择非投掷内存分配。如果您对异常过敏,那么您必须使用向量的另一个实现 - 或者您决定使用的任何容器。但是,您不需要任何带有mmap的容器。

  

不处理异常会破坏性能吗?

幸运的是,与从磁盘读取数百GB相比,运行时异常成本微不足道。

  

运行sysinfo()并在加载文件之前检查空闲RAM是否更好?

sysinfo调用可能比处理异常要慢(我没有测量过,这只是一个猜想) - 并且它不会告诉您可能存在的特定于进程的限制。

  

而且,重复尝试加载文件,捕获异常并尝试加载较小的文件(需要递归?)看起来很难并且代价高昂。

不需要递归。如果您愿意,可以使用它;它可以用尾调用来编写,可以优化掉。

  

关于内存映射:我前一段时间看过它,发现无聊处理。需要使用C的open()和所有内容,然后再告诉std :: fstream。

映射内存后,它比std::fstream更容易使用。您可以跳过复制到矢量部分,只需使用映射的内存,就好像它是已经存在于内存中的数组一样。

  

看起来使用std :: fstream部分读取文件的最佳方法是派生std :: streambuf

我不明白为什么你需要得到任何东西。只需使用std::basic_fstream::seekg()跳到您想要阅读的部分。

答案 1 :(得分:2)

作为@user2097303's answer的补充,我想补充说vector保证连续分配。对于长时间运行的应用程序,这将导致内存碎片,最终,将不再存在连续的内存块,尽管在块之间,有足够的空间是免费的。

因此,最好将数据存储到deque