C++ 内存不足:改为写入文件,在需要时读取数据?
Posted
技术标签:
【中文标题】C++ 内存不足:改为写入文件,在需要时读取数据?【英文标题】:Not enough memory in C++ : write to file instead, read data in when needed? 【发布时间】:2015-07-07 16:42:39 【问题描述】:我正在用 C++ 在 Linux 机器上开发一种用于小波图像分析和机器学习的工具。 它受到图像大小、N 个方向中每个方向的尺度数量及其对应的过滤器(最多 2048x2048 双倍)以及机器学习算法的额外内存和处理开销的限制。
不幸的是,我的 Linux 系统编程技能充其量是肤浅的, 所以我目前没有使用交换,但认为它应该是可能的?
我需要保持虚部和实部 每个尺度和方向的过滤图像,以及用于重建目的的相应小波。我将它们保存在内存中以提高小图像的速度。
关于内存使用:我已经
所有内容都存储一次, 只有需要的, 删除任何重复条目或冗余, 仅供参考, 在临时对象上使用指针, 在不再需要内存时立即释放内存并且 将计算次数限制在绝对最小值。与大多数数据处理工具一样,速度至关重要。只要有 内存是否足够,该工具的速度大约是 Matlab 代码中相同实现的 3 倍。
但是一旦我失去记忆,就什么都没有了。不幸的是,我训练算法的大多数图像都很大(原始数据 4096x4096 双条目,对称填充后更大),因此我经常碰到天花板。
暂时将当前计算/处理步骤不需要的数据从内存写入磁盘会是不好的做法吗?
哪种方法/数据格式最适合这样做? 我正在考虑使用 rapidXML 读取 XML 并将其写入二进制文件,然后只读取所需的数据。这行得通吗? 我需要内存映射文件吗? https://en.wikipedia.org/wiki/Memory-mapped_file我知道这会导致性能损失,但更重要的是软件运行流畅且不会死机。
我知道有一些库可以进行小波图像分析,所以请不要说“为什么要重新发明***,只用 XYZ 代替”。我正在使用非常特定的小波,我需要自己做,我不应该使用外部库。
【问题讨论】:
忘记 XML。最适合用作临时存储的数据格式与您在内部使用的数据格式相同——您可以使用fread
和fwrite
或您的操作系统平台特定函数存储大量算术类型(包括复数对) (通常允许您提示预读缓存)
或者使用一些中性的二进制序列化格式,比如 XDR
您可能想要使用一些索引文件库,例如GDBM,或者可能使用sqlite。您是否提前知道内存访问模式(即,您是否能够在循环 i 处知道循环 i+1 或 i+2 所需的数据,或者它是否足够随机以可预测)?
顺便说一句,这通常是让您的软件成为免费软件(并将其发布到例如github.com ...)可以帮助您很大的情况。
让我们continue this discussion in chat。
【参考方案1】:
是的,将数据写入磁盘以节省内存是不好的做法。
通常无需手动将数据写入磁盘以节省内存,除非您已达到可处理的极限(32 位机器上为 4GB,64 位机器上更多)。
原因是操作系统已经在做同样的事情。您自己的解决方案很可能比操作系统正在做的要慢。如果您不熟悉分页和虚拟内存的概念,请阅读this Wikipedia article。
【讨论】:
嗯,我有 8GB 的 RAM,并且没有任何泄漏(针对我的代码运行 Valgrind)。如前所述,我也没有(明显的)冗余,所以我确实有内存问题 - 访问它不是问题。我唯一可以改进的(如我的帖子中提到的)是将当前处理步骤不需要的数据临时存储在磁盘上或我的应用程序之外。 对不起,我没有解决您内存不足的问题。您确定您的冻结是由于内存不足引起的吗?如果您使用 64 位并且有一个足够大的交换分区,那么操作系统应该在内存不足之前就开始将数据写入磁盘。物理内存的大小与应用程序可以寻址多少内存无关。【参考方案2】:您是否考虑过使用 mmap 和 munmap 将图像(和临时结果)带入您的地址空间并在您不再需要它们时丢弃它们。 mmap 允许您将 file 的内容直接映射到内存中。没有更多的 fread/fwrite。直接内存访问。对内存区域的写入也会被写回文件,并且稍后恢复该中间状态并不比重做 mmap 更难。
最大的优势是:
-
没有像 XML 这样臃肿的格式编码
非常适合瞬态结果,例如在连续内存区域中表示的矩阵。
实施起来非常简单。
将何时换入和换出的决定完全委托给操作系统。
【讨论】:
但是,如果您想处理比 RAM 更多的数据,madvise
非常重要【参考方案3】:
这并不能解决您的基本问题,但是:您确定需要以双精度执行所有操作吗?您可能无法使用整数系数小波,但将图像数据本身存储为双精度通常非常浪费。此外,4k 图像不是很大……我假设您实际上正在使用某种帧,因此有多余的条目,否则您的数字似乎不会加起来(并且您是否将它们稀疏地存储?).. . 或者您可能只是一次使用大量数字。
至于“我应该写入磁盘”吗?这会有所帮助,特别是如果您通过将图像数据提高到双精度来获得 4 倍(或更多)的增长。不过,您可以自己回答,只需测量加载时间并与您的计算时间进行比较,看看这是否值得追求。小波本身应该很便宜,所以我猜你主要受你的学习算法支配。在这种情况下,请继续丢弃原始数据或其他任何内容,直到您再次需要它为止。
【讨论】:
以上是关于C++ 内存不足:改为写入文件,在需要时读取数据?的主要内容,如果未能解决你的问题,请参考以下文章
C++ 优先队列push()时,出现内存不足,怎么办,能又啥办法解决吗