使用了太多的内存(我认为)

Using too much memory (I think)

本文关键字:内存 太多      更新时间:2023-10-16

我正试图运行一个程序来分析一堆包含数字的文本文件。文本文件的总大小约为12 MB,我从360个文本文件中的每一个文件中提取1000个替身,并将它们放入一个向量中。我的问题是,我已经完成了文本文件列表的一半,然后我的计算机速度减慢,直到不再处理任何文件。这个程序不是无限循环的,但我认为我有使用太多内存的问题。有没有更好的方法来存储这些数据,而不会占用那么多内存?

其他可能相关的系统信息:

运行Linux

8 GB内存

安装了Cern ROOT框架(我不知道如何减少内存占用)

Intel Xeon四核处理器

如果你需要其他信息,我会更新这个列表

编辑:我运行了top,我的程序使用了更多的内存,一旦它达到80%以上,我就把它杀死了。有很多代码,所以我会挑选出内存分配的位置等等。编辑2:我的代码:

void FileAnalysis::doWork(std::string opath, std::string oName)
{
//sets the ouput filepath and the name of the file to contain the results
outpath = opath;
outname = oName;
//Reads the data source and writes it to a text file before pushing the filenames into a vector
setInput();
//Goes through the files queue and analyzes each file
while(!files.empty())
{
    //Puts all of the data points from the next file onto the points vector then deletes the file from the files queue
    readNext();
    //Places all of the min or max points into their respective vectors
    analyze();
    //Calculates the averages and the offset and pushes those into their respective vectors
    calcAvg();
}
makeGraph();
}
//Creates the vector of files to be read
void FileAnalysis::setInput()
{
string sysCall = "", filepath="", temp;
filepath = outpath+"filenames.txt";
sysCall = "ls "+dataFolder+" > "+filepath;
system(sysCall.c_str());
ifstream allfiles(filepath.c_str());
while (!allfiles.eof())
{
    getline(allfiles, temp);
    files.push(temp);
}
}
//Places the data from the next filename into the files vector, then deletes the filename from the vector
void FileAnalysis::readNext()
{
cout<<"Reading from "<<dataFolder<<files.front()<<endl;
ifstream curfile((dataFolder+files.front()).c_str());
string temp, temptodouble;
double tempval;
getline(curfile, temp);
while (!curfile.eof())
{
    if (temp.size()>0)
    {
        unsigned long pos = temp.find_first_of("t");
        temptodouble = temp.substr(pos, pos);
        tempval = atof(temptodouble.c_str());
        points.push_back(tempval);
    }
    getline(curfile, temp);
}
setTime();
files.pop();
}
//Sets the maxpoints and minpoints vectors from the points vector and adds the vectors to the allmax and allmin vectors
void FileAnalysis::analyze()
{
for (unsigned int i = 1; i<points.size()-1; i++)
{
    if (points[i]>points[i-1]&&points[i]>points[i+1])
    {
        maxpoints.push_back(points[i]);
    }
    if (points[i]<points[i-1]&&points[i]<points[i+1])
    {
        minpoints.push_back(points[i]);
    }
}
allmax.push_back(maxpoints);
allmin.push_back(minpoints);
}
//Calculates the average max and min points from the maxpoints and minpoints vector and adds those averages to the avgmax and avgmin vectors, and adds the offset to the offset vector
void FileAnalysis::calcAvg()
{
double maxtotal = 0, mintotal = 0;
for (unsigned int i = 0; i<maxpoints.size(); i++)
{
    maxtotal+=maxpoints[i];
}
for (unsigned int i = 0; i<minpoints.size(); i++)
{
    mintotal+=minpoints[i];
}
avgmax.push_back(maxtotal/maxpoints.size());
avgmin.push_back(mintotal/minpoints.size());
offset.push_back((maxtotal+mintotal)/2);
}

编辑3:我添加代码是为了保留向量空间,我添加代码也是为了关闭文件,但在程序停止之前,我的内存仍然被填满了96%。。。

这可以无限优化,但我的即时反应是使用矢量以外的容器。请记住,向量的存储是在内存中串行分配的,这意味着如果没有足够的当前空间来容纳新元素,则添加额外的元素会导致整个向量的重新分配

请尝试为常量插入优化的容器,例如队列或列表。

或者,如果需要vector,您可以尝试预先分配预期的内存占用空间,以避免连续的重新分配。请参见vector.reserve():矢量。请注意,保留容量是以元素表示的,而不是字节。

int numberOfItems = 1000;
int numberOfFiles = 360;
size_type totalExpectedSize = (numberOfItems) * (numberOfFiles);
myVector.reserve( totalExpectedSize );

----------编辑以下代码张贴---------------

我最关心的是analyze()中的以下逻辑:

for (unsigned int i = 1; i<points.size()-1; i++) 
{     
    if (points[i]>points[i-1]&&points[i]>points[i+1])     
    {         
        maxpoints.push_back(points[i]);     
    }     
    if (points[i]<points[i-1]&&points[i]<points[i+1])     
    {         
        minpoints.push_back(points[i]);     
    } 
} 
allmax.push_back(maxpoints); 
allmin.push_back(minpoints); 

具体来说,我关心的是allmax和allmin容器,您要将maxpoints和minpoints容器的副本推送到它们上面。根据数据集的不同,使用这种逻辑,maxpoints和minpoints容器本身可能会变得相当大。

您要承担多次容器复制的成本。真的有必要将minpoints/maxpoints容器复制到allmax/allmin中吗?如果不了解更多信息,就很难优化您的存储设计。

我在任何地方都看不到minpoints和maxpoints实际上被清空了,这意味着随着时间的推移,它们可能会变得非常大,并且它们到allmin/allmax容器的相应副本也会变得很大。minpoints/maxpoints是否应该仅代表一个文件的min/max点?

举个例子,让我们看看一个简化的minpoints和allmin场景(但请记住,这也适用于max,两者的规模都比这里显示的要大)。显然,这是一个旨在表明我观点的数据集:

File 1: 2 1 2 1 2 1 2 1 2 1 2
minpoints: [1 1 1 1 1]
allmin:    [1 1 1 1 1]
File 2: 3 2 3 2 3 2 3 2 3 2 3
minpoints: [1 1 1 1 1 2 2 2 2 2]
allmin:    [1 1 1 1 1 1 1 1 1 1 2 2 2 2 2]
File 3: 4 3 4 3 4 3 4 3 4 3 4
minpoints: [1 1 1 1 1 2 2 2 2 2 3 3 3 3 3]
allmin:    [1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3]

还有其他的优化和批评需要进行,但现在我将其限制在试图解决您的直接问题上。你能发布makeGraph()函数,以及所有容器的定义吗?

要尝试的几件事:

  1. 运行top,查看程序使用了多少内存
  2. valgrind下运行一个较小的问题示例(例如,从1个文件中读取10个浮点值),并检查内存泄漏
  3. 使用reserve()预先分配所需矢量的大小(高估)
  1. 检查内存使用情况是否符合预期,即是否没有泄漏资源(是否未能释放任何内存或关闭任何文件?)
  2. 试着预先将向量保留为所需的完整大小,看看它是否正确分配
  3. 你需要一次把所有的结果都存储在内存中吗?你能把它们写进一个文件吗

如有必要,您可以尝试:

  • 使用比double更小的数据类型
  • 使用数组(如果您担心开销)而不是向量
  • 如果你担心内存碎片,可以使用向量的链表

但这不应该是必要的(或者更有成效),正如我所同意的,你所做的听起来应该奏效。

查看您的代码和迭代次数。如果你有太多的迭代而没有Sleep或基于事件的编程,那么你的进程可能会消耗很多CPU。。

预先分配向量的元素数量,使向量无需重新分配。。但这将是过度杀伤

由于大部分程序都消耗CPU,因此将进程作为后台运行,并使用top命令查看程序的CPU和内存使用情况。

readNext()方法中使用eof()可能会遇到问题。例如,请参阅这个SO问题和C++常见问题解答中的15.4/15.5节。如果这确实是这个问题,那么修复读取循环以检查getline()的返回状态应该可以解决这个问题。

如果没有,我会从调试开始,看看程序在哪里/如何"崩溃"。在这种情况下,我可能会通过printf()简单地记录控制台或日志文件,并每隔1000行输出当前文件和状态。让它运行几次,并检查日志输出是否有任何明显的故障迹象(即,它从未通过读取文件#3)。

如果这还不足以暴露问题,那么在必要的位置添加更详细的日志记录和/或进入调试器并开始跟踪(当你对代码的概念与计算机不同时,我们经常阅读我们认为代码应该做什么,而不是它实际说的)。