1

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

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

运行 Linux

8 GB 内存

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

英特尔至强四核处理器

如果您需要其他信息,我将更新此列表

编辑:我跑了 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%...

4

5 回答 5

4

这可以无休止地优化,但我的直接反应是使用 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 是否应该代表一个文件的最小/最大点?

作为一个例子,让我们看一个简化的 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()函数,以及所有涉及的容器的定义(点、最小点、最大点、allmin、allmax)吗?

于 2011-06-13T17:03:47.707 回答
3

有几件事要尝试:

  1. 运行top以查看您的程序正在使用多少内存。
  2. 在下面运行一个较小的问题示例(例如,从 1 个文件中读取 10 个浮点数)valgrind并检查内存泄漏。
  3. 使用预分配所需的向量大小(高估)reserve()
于 2011-06-13T17:12:00.353 回答
0

查看您的代码和迭代次数。如果您在没有睡眠或基于事件的编程的情况下进行如此多的迭代,您的进程可能会消耗大量 CPU。

或者

为向量预先分配元素的数量,这样向量就不需要重新分配了。但这将是矫枉过正

由于大多数情况下您的程序会消耗 CPU,因此请在后台运行您的进程并使用 top 命令查看程序的 CPU 和内存使用情况。

于 2011-06-13T17:13:48.080 回答
0
  1. 检查内存使用情况是否符合您的预期,即。你没有泄漏资源(你没有释放任何内存,没有关闭任何文件?)
  2. 尝试将向量保留为您预先需要的完整大小,并查看它是否正确分配。
  3. 您是否需要一次将所有结果存储在内存中?您可以将它们写入文件吗?

如有必要,您可以尝试:

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

但这不应该是必要的(或没有生产力),因为我同意,你正在做的事情听起来应该有效。

于 2011-06-13T17:19:26.737 回答
0

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

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

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

于 2011-06-13T19:26:14.900 回答