Используя слишком много памяти (я думаю) - PullRequest
1 голос
/ 13 июня 2011

Я пытаюсь запустить программу, которая анализирует кучу текстовых файлов, содержащих числа. Общий размер текстовых файлов составляет ~ 12 МБ, и я беру 1000 дубликатов из каждого из 360 текстовых файлов и помещаю их в вектор. Моя проблема в том, что я получаю примерно половину списка текстовых файлов, и затем мой компьютер замедляется, пока он не перерабатывает больше файлов. Программа не является бесконечным циклом, но я думаю, что у меня проблема с использованием слишком большого количества памяти. Есть ли лучший способ хранить эти данные, которые не будут использовать столько памяти?

Другая, возможно, соответствующая системная информация:

Под управлением Linux

8 ГБ памяти

Установлена ​​платформа Cern ROOT (хотя я не знаю, как уменьшить объем памяти при этом)

Четырехъядерный процессор Intel Xeon

Если вам нужна другая информация, я обновлю этот список

РЕДАКТИРОВАТЬ: я побежал, и моя программа использует больше памяти, и как только она превысила 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%, прежде чем программа останавливается ...

Ответы [ 5 ]

4 голосов
/ 13 июня 2011

Это можно оптимизировать бесконечно, но моя немедленная реакция - использовать контейнер, отличный от вектора.Помните, что память для вектора распределяется последовательно в памяти, что означает, что добавление дополнительных элементов вызывает перераспределение всего вектора, если не хватает текущего пространства для хранения новых элементов.

Попробуйте контейнер, оптимизированный для постоянных вставок, такой как очередь или список.

В качестве альтернативы, если требуется вектор, вы можете попытаться выделить ожидаемый объем памяти заранее, чтобы избежать непрерывного перераспределения.См. 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?Не зная немного больше, трудно оптимизировать дизайн хранилища.

Я нигде не вижу, чтобы минпоинты и макспойнты фактически опустошались, что означает, что со временем они могут вырасти очень большими, а их соответствующие копииконтейнеры allmin / allmax вырастут очень большими.Должны ли minpoints / maxpoints представлять минимальные / максимальные точки для только одного файла ?

В качестве примера давайте рассмотрим упрощенный сценарий minpoints и allmin (но имейте в виду, что это применимок макс точно так же, и оба в большем масштабе, чем показано здесь).Это, очевидно, набор данных, разработанный для того, чтобы показать мою точку зрения:

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)?

3 голосов
/ 13 июня 2011

Несколько вещей, которые нужно попробовать:

  1. Запустите top, чтобы узнать, сколько памяти использует ваша программа.
  2. Запустите небольшой пример проблемы (например, прочитайте 10 floatиз 1 файла) в valgrind и проверьте на утечки памяти.
  3. Предварительно выделите необходимый размер вектора (завышение), используя reserve()
0 голосов
/ 13 июня 2011

Возможно, у вас возникла проблема с использованием eof() в вашем методе readNext(). Например, см. этот вопрос SO и раздел 15.4 / 15.5 в C ++ FAQ. Если это действительно такая проблема, то исправление цикла чтения для проверки состояния возврата getline() должно устранить проблему.

Если этого не произойдет, я начну с отладки, чтобы увидеть, где / как происходит сбой программы. В таком случае я бы, вероятно, начал с простой регистрации через printf() в консоли или в файле журнала и выводил текущий файл и состояние через каждые 1000 строк. Пусть он запустится несколько раз и проверит вывод журнала на наличие каких-либо явных признаков проблем (то есть он никогда не пройдет чтение файла № 3).

Если этого недостаточно для выявления проблемы, то добавьте более подробное ведение журнала в нужных местах и ​​/ или прорвитесь в отладчик и начните трассировку (полезно, когда ваша концепция кода отличается от компьютеров, мы часто читаем думаю, что код должен делать вместо того, что он на самом деле говорит).

0 голосов
/ 13 июня 2011
  1. Проверьте использование памяти, что вы ожидаете, т.е.что у вас нет утечек ресурсов (вам не удается освободить память, не закрыть какие-либо файлы?)
  2. Попробуйте зарезервировать вектор в полном размере, необходимом вам заранее, и посмотрите, правильно ли он выделяется.
  3. Нужны ли вам все результаты в памяти сразу?Можете ли вы записать их в файл вместо этого?

При необходимости вы можете попробовать:

  • , используя меньший тип данных, чем double
  • , используя массив (если вы беспокоитесь о накладных расходах) вместо вектора
  • , используя связанный список векторов, если вы беспокоитесь о фрагментации памяти

Но это не должно быть необходимым (или быть coutnerproductive), как я согласен, то, что вы делаете, звучит так, как будто это должно работать.

0 голосов
/ 13 июня 2011

Посмотрите на ваш код и количество итераций.ваш процесс может потреблять много ресурсов ЦП, если у вас так много итераций без программирования Sleep или событий ..

ИЛИ

Предварительно выделите количество элементов для вектора, чтобы вектор не нуждалсяперераспределить .. Но это будет излишним

Поскольку в основном ваша программа использует ЦП, запустите ваш процесс в качестве фона и используйте команду top, чтобы увидеть использование ЦП и памяти вашей программой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...