C++ c++;大文件上的疯狂内存消耗

C++ c++;大文件上的疯狂内存消耗,c++,memory,memory-management,memory-leaks,ubuntu-12.04,C++,Memory,Memory Management,Memory Leaks,Ubuntu 12.04,我正在将一个10GB的文件加载到内存中,我发现即使我去掉任何额外的开销,只将数据存储在一个阵列中,它仍然会占用53GB的ram。这对我来说似乎很疯狂,因为我正在将一些文本数据转换为占用更少空间的long,并将其余的转换为char*,char*应该占用与文本文件相同的空间。我试图加载的文件中有大约1.5亿行数据。当我按照下面的方式加载时,有什么原因会占用这么多内存吗 这里有三个文件:一个fileLoader类及其头文件和一个简单运行它们的main。 要回答一些问题: 操作系统是UBUNTU 12.

我正在将一个10GB的文件加载到内存中,我发现即使我去掉任何额外的开销,只将数据存储在一个阵列中,它仍然会占用53GB的ram。这对我来说似乎很疯狂,因为我正在将一些文本数据转换为占用更少空间的long,并将其余的转换为char*,char*应该占用与文本文件相同的空间。我试图加载的文件中有大约1.5亿行数据。当我按照下面的方式加载时,有什么原因会占用这么多内存吗

这里有三个文件:一个fileLoader类及其头文件和一个简单运行它们的main。 要回答一些问题: 操作系统是UBUNTU 12.04 64位 这是在一个带有64GB内存的machien和一个SSD hd上,我为RAM提供了64GB的交换空间 由于速度的需要,我一次加载所有数据。这对应用程序至关重要。所有排序、索引和大量数据密集型工作都在GPU上运行。 另一个原因是,一次加载所有数据使我编写代码更加简单。我不必担心索引文件,例如映射到另一个文件中的位置

以下是头文件:

#ifndef FILELOADER_H_
#define FILELOADER_H_
#include <iostream>
#include <fstream>

#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <string>

class fileLoader {
public:
    fileLoader();
    virtual ~fileLoader();
    void loadFile();
private:
    long long ** longs;
    char *** chars;
    long count;
    long countLines(std::string inFile);
};


#endif /* FILELOADER_H_ */
以下是我正在加载的数据示例:

13|0|1|1997|113|1|4|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
14|0|1|1997|113|1|5|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
15|0|1|1997|113|1|6|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
16|0|1|1997|113|1|7|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
17|0|1|1997|113|1|8|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
18|0|1|1997|113|1|9|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
19|0|1|1997|113|1|10|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
20|0|1|1997|113|1|11|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
21|0|1|1997|113|1|12|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
9|0|1|1997|113|1|13|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
27|0|1|1992|125|1|1|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
28|0|1|1992|125|1|2|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
29|0|1|1992|125|1|3|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
30|0|1|1992|125|1|4|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
31|0|1|1992|125|1|5|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
32|0|1|1992|125|1|6|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
33|0|1|1992|125|1|7|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
34|0|1|1992|125|1|8|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
35|0|1|1992|125|1|9|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
36|0|1|1992|125|1|10|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
37|0|1|1992|125|1|11|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
38|0|1|1992|125|1|12|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
39|0|1|1992|125|1|13|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
40|0|1|1992|125|1|14|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
41|0|1|1992|125|1|15|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
10|0|1|1996|126|1|1||||||

您创建的每个对象和字符串都有各自的内存管理开销。因此,从第2列加载字符串“0”,这取决于内存管理器,可能需要两到四个完整单词(可能更多)。将其称为16到32字节的存储空间来保存一个单字节字符串。然后从第3列加载“1”。等等

您为每行分配了九块内存,因此总共分配了13.5亿块内存。这些分配有一定的开销,通常至少是指针大小的两倍,甚至更多。在64位机器上,这已经是16个字节,因此您将获得21.6GB的开销

除此之外,还有堆碎片和对齐的开销:即使您只在其中存储字符串,分配器也必须对齐内存分配,以便您可以在其中存储尽可能大的值,而不会触发未对齐。对齐可能取决于CPU的向量单元,这可能需要非常重要的对齐,16字节对齐并不少见


使用16字节分配开销和16字节对齐进行计算,在没有原始数据的情况下得到43.2 GB的分配。根据原始数据,此计算已经非常接近您的测量值。

如何测量内存消耗?使用htop,我还没有使用任何内存管理工具。我对C++非常陌生,我是一个java开发者。因此,我只看到消耗了多少ram,但当我加载数据时,峰值是从2GB到56GB。为什么要将10GB加载到内存中?我不认为这是真的。有很多更好的数据处理方法您是否有53gb的ram?64GB的交换加上64GB的ram。Ed我已经将它加载到内存中,因为我可以通过这种方式非常快速地对它进行索引,从而允许我对数据执行需要执行的操作。连接不同的数据集,然后根据数据和目标创建归纳决策树。我已经让它工作了,只要我只坚持数字,尽管我最终使用了大约64GB的RAN和另一个20GB的swap来处理我当前的数据集。我需要开始分析这个字符,它会比我在这个平台上能处理的要大。这看起来有很多开销,让我把它弄清楚。因此,除了数据之外,我存储的每个字符*和每行长的值都有一个8字节的指针。在我看来,我只需要56字节的字符和8字节每长。那么这将是9.6GB,不是吗?是的。分配非常多非常小的对象是非常浪费的。看一下第一个答案。考虑定义一个结构,该结构对于文件中的每个列有一个字段,并将数据存储为这些结构的向量。对于值总是相同长度的字符串列,使用
char[n]
而不是动态分配的
char*
。您能否快速解释一下,为什么定义用于封装此数据的结构比这些公认的非常愚蠢的巨大数组更有效。我之所以创建数组,是因为我实际上认为它们比我实现的包含它的类消耗更少的内存。定义结构只有在可以为其中的字符串定义存储的情况下才有帮助(因此每个字符串必须具有已知的最大长度)。如果你这样做,你只为每一行分配一个大的“对象”,这样一对字(或者可能只是四舍五入到一个16字节的边界)的开销就会减少。谢谢!我想我已经理解了为什么会这样,以及我可以采取哪些措施来提高我的内存消耗(例如,将所有字符存储在一起)。所以最大的问题就像别人说的。做很多小的分配是不好的。+1我数了10次,但我开始感到头晕,所以我可能重复数了一些东西。
#include "fileLoader.h"

int main()
{

fileLoader loader;
loader.loadFile();
return 0;
}
13|0|1|1997|113|1|4|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
14|0|1|1997|113|1|5|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
15|0|1|1997|113|1|6|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
16|0|1|1997|113|1|7|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
17|0|1|1997|113|1|8|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
18|0|1|1997|113|1|9|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
19|0|1|1997|113|1|10|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
20|0|1|1997|113|1|11|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
21|0|1|1997|113|1|12|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
9|0|1|1997|113|1|13|12408012|C9FF921CA04ADA3D606BF6DAC4A0B092|SEMANAL|66C5E828DC69F857ADE060B8062C923E|113|1
27|0|1|1992|125|1|1|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
28|0|1|1992|125|1|2|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
29|0|1|1992|125|1|3|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
30|0|1|1992|125|1|4|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
31|0|1|1992|125|1|5|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
32|0|1|1992|125|1|6|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
33|0|1|1992|125|1|7|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
34|0|1|1992|125|1|8|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
35|0|1|1992|125|1|9|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
36|0|1|1992|125|1|10|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
37|0|1|1992|125|1|11|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
38|0|1|1992|125|1|12|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
39|0|1|1992|125|1|13|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
40|0|1|1992|125|1|14|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
41|0|1|1992|125|1|15|10183|9EF534D2CF74B24AC28CBD9BE937A412|SEMANAL|375CCE505F5353CCDE85D4E84A9888D8|125|1
10|0|1|1996|126|1|1||||||