синтаксический анализ файла с использованием слишком большого объема памяти (C ++) - PullRequest
2 голосов
/ 09 ноября 2011

У меня есть программа, которая отображает вещи из файлов .raw, вот пример:

1.000000 1.000000 -1.000000 1.000000 -1.000000 -1.000000 -1.000000 -1.000000 -1.000000 -1.000000 1.000000 -1.000000 
1.000000 0.999999 1.000000 -1.000000 1.000000 1.000000 -1.000000 -1.000000 1.000000 0.999999 -1.000001 1.000000 
1.000000 1.000000 -1.000000 1.000000 0.999999 1.000000 0.999999 -1.000001 1.000000 1.000000 -1.000000 -1.000000 
1.000000 -1.000000 -1.000000 0.999999 -1.000001 1.000000 -1.000000 -1.000000 1.000000 -   1.000000 -1.000000 -1.000000 
-1.000000 -1.000000 -1.000000 -1.000000 -1.000000 1.000000 -1.000000 1.000000 1.000000 - 1.000000 1.000000 -1.000000 
1.000000 0.999999 1.000000 1.000000 1.000000 -1.000000 -1.000000 1.000000 -1.000000 -1.000000 1.000000 1.000000 

Это просто грани куба, моя проблема в том, что этот файл имеет размер 650 байт, теперь, когда я загружаю программу, программа занимает 20 МБ. Это не такая большая проблема, но при загрузке гораздо больших файлов это может стать большой проблемой.

Вот код для моего файлового выражения (извините, если он грязный, я совершенно не знаком с C ++):

/*
 * PhraseObj.cpp
 *
 *  Created on: Nov 5, 2011
 *      Author: tom
 */

#include "PhraseObj.h"

#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "obj.h"

PhraseObj::PhraseObj(string file)
{
    FILE.open(file.c_str());
    cout << FILE.is_open() << "\n";
}

obj PhraseObj::getObj()
{
    string line;
    Polygon P;
    vertex V;
    obj O;
    int place;
    int NextPos;
    float x;
    float y;
    float z;
    getline(FILE, line);
    while (!FILE.eof()) {

        cout << "new line" << "\n";

        place = 0;
        while (place != string::npos) {
            if (place == (line.length() - 1)) {
                break;
            }

            NextPos = line.find(" ", place + 1);
            line.substr(place, (NextPos - place) - 1);
            cout << line.substr(place, (NextPos - place) - 1).c_str() << " ";
            x =::atof(line.substr(place, (NextPos - place) - 1).c_str());

            V.x(x);
            cout << x << "\n";

            place = NextPos;
            NextPos = line.find(" ", place + 1);
            line.substr(place, NextPos - place);
            cout << line.substr(place + 1, (NextPos - place) - 1).c_str() << " ";
            y =::atof(line.substr(place + 1, (NextPos - place) - 1).c_str());
            V.y(y);
            cout << y << "\n";

            place = NextPos;
            NextPos = line.find(" ", place + 1);
            line.substr(place + 1, NextPos - place);
            cout << line.substr(place + 1, (NextPos - place) - 1).c_str() << " ";
            z =::atof(line.substr(place + 1, (NextPos - place) - 1).c_str());
            V.z(z);
            cout << z << "\n";

            P.addPoint(V);
            place = line.find(" ", place + 1);
            cout << "place: " << place << " " << "length:" << line.length() << "\n";
        }
        getline(FILE, line);
        O.AddPolygon(P);
    }
    cout << "returning" << "\n";
    try {
        return O;
    }
    catch(bad_alloc & ba) {
        cout << "bad_alloc caught: " << ba.what() << endl;
    }
}

void PhraseObj::closeFile()
{
    FILE.close();
}

bool PhraseObj::isEnd()
{
    return FILE.eof();
}

Несколько примечаний, вершины - это числа с координатами x, y и z.
Многоугольник - это вектор вершин.
Объект является вектором многоугольника.

Спасибо, Том.

и vertex.h:

/*
 * vertex.h
 *
 *  Created on: Oct 26, 2011
 *      Author: tom
 */

#ifndef VERTEX_H_
#define VERTEX_H_


class vertex {
float x_;
float y_;
float z_;
public:
//here are some getters
float x() {return x_;} ;
float y() {return y_;} ;
float z() {return z_;} ;
// and now for some setters
void x(float _x) {x_ = _x;} ;
void y(float _y) {y_ = _y;} ;
void z(float _z) {z_ = _z;} ;
};


#endif /* VERTEX_H_ */

и polygon.cpp:

/*
 * Polygon.cpp
 *
 *  Created on: Oct 26, 2011
 *      Author: tom
 */

#include "Polygon.h"


using namespace std;

void Polygon::addPoint(vertex V) {
point.push_back(V);
}

int Polygon::getNumOfPoints() {
return point.size();
}

 vertex Polygon::getPoint(int I) {
return point.at(I);
 }

Ответы [ 4 ]

1 голос
/ 09 ноября 2011

Похоже, ваш код не так уж и плох.Единственная проблема, которую я вижу, состоит в том, что вы создаете много промежуточных объектов, каждый из которых вызывает определенное выделение памяти (поскольку вы использовали RAII, хорошо!), Это не вызывает утечек памяти.НО современные распределители памяти не возвращают освобожденную память операционной системе немедленно, а сохраняют ее для дальнейших запросов на выделение ресурсов для ответа оттуда.Так что вы, возможно, просто испытали это.

Конечно, вам следует избегать создания этих ненужных посредников.Например, ваш код содержит множество line.substr(place + 1, NextPos - place);, где вы не назначаете полученную строку ни для чего.Таким образом, std::string приходит в себя и разрушается, когда его никогда не используют.

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

1 голос
/ 09 ноября 2011

Я не знаю, почему вы наблюдаете такое чрезмерное использование памяти, так что это не совсем ответ на ваш вопрос, но я хотел бы отметить, что вы можете значительно упростить свою функцию PhraseObj::getObj(), используяstd::istringstream и std::istream_iterator объекты:

obj PhraseObj::getObj()
{
    obj O;
    string line;
    while ( getline( FILE, line ) ) {
        istringstream vertices( line );
        istream_iterator<double> it( vertices ), end;

        Polygon p;
        for ( int i = 0; i < 4; ++i ) {
            Vertex v;
            v.x( *it++ );
            v.y( *it++ );
            v.z( *it++ );
            p.addPoint( v );
        }

        O.AddPolygon( p );
    }        
}

Вместо перехода от одного пробела к следующему с использованием методов std::string, вы можете вставить строку в объект istringstream и затем использовать istream_iterator<double> объекты для итерации отдельных вершин.Если вы знаете, что у вас всегда есть 12 координатных вершин на линию (три на вершину, четыре вершины на многоугольник), то вы можете использовать простой цикл для их чтения.

0 голосов
/ 09 ноября 2011

Единственная проблема, которую я вижу, это то, что вы проверяете на EOF после чтения с getline(), вы должны изменить цикл while с помощью do ... while.Кроме того, этот код не подходит для показа нам.Возможно, объявления классов для Polygon и Vertex имеют большие возможности для работы с утечками памяти ... Вы используете vector <> из STL?

Еще одна вещь, которую вы должны принять во внимание, поскольку вы не сказали, как пришли к выводу, что слишком много памяти тратится впустую.Возможно, эти 20 Мбайт являются частью стандартной памяти, выделяемой любому процессу в вашей операционной системе.Если вы действительно хотите знать, как используется память, вам необходим инструмент профилирования, например, valgrind .

0 голосов
/ 09 ноября 2011

Если вы сохраните его как двоичное представление чисел с плавающей запятой, ваши размеры файлов, время загрузки, время разбора, память и т. Д. Резко сократятся.

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

...