2013-07-25 4 views
1

Я работаю над программой, и у меня есть утечка памяти, которую я просто не могу прибить. Я тоже не очень разбираюсь в C/C++. Я отправлю ОДИН из ошибок valgrind и определений классов и функций, которые являются релевантными ... если я что-то забуду, просто спрошу, и я буду обновлять :) Причина, по которой я не публикую весь отчет valgrind, есть много их, но они схожи ... единственная разница - это трассировка стека.Не удается найти утечку памяти, обнаруженную Valgrind

Я начал разрабатывать его довольно плохо, поэтому, чтобы исправить утечки памяти, моя идея состояла в том, чтобы создать глобальную фабрику для добавления моих объектов, чтобы удалить их позже. Я заменил каждое появление «нового» на заводский метод для его создания .. в этом случае это класс Column. Я уверен, что каждый объект, созданный makeColumn, удаляется, поскольку я использую вектор для хранения указателя. Функция для итерации по вектору и удаления каждого элемента в нем. Вызывается до завершения программы.

Этот отчет valgrind заставляет меня думать, что каким-то образом нить не освобождается. Я устанавливаю переменную GLIBCXX_FORCE_NEW, и она не имеет никакого отношения к обнаруженным утечкам. Я использую gcc 4.7.2.

Кроме того, да, я получаю информацию от созданного ANTLR парсера ... это, вероятно, не имеет значения, поскольку ANTLR обрабатывает его собственную память. Указатели char являются единственными данными ANTLR.

==23168== 15 bytes in 1 blocks are definitely lost in loss record 10 of 30 
==23168== at 0x4ACE73C: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) 
==23168== by 0x4BA62A3: std::string::_Rep::_S_create(unsigned int, unsigned int, std::allocator<char> const&) (in /usr/lib32/libstdc++.so.6.0.17) 
==23168== by 0x4BA75EE: std::string::_Rep::_M_clone(std::allocator<char> const&, unsigned int) (in /usr/lib32/libstdc++.so.6.0.17) 
==23168== by 0x4BA7F3F: std::string::assign(std::string const&) (in /usr/lib32/libstdc++.so.6.0.17) 
==23168== by 0x4BA7F92: std::string::operator=(std::string const&) (in /usr/lib32/libstdc++.so.6.0.17) 
==23168== by 0x82E0B57: GenericFactory::makeColumn(char const*, char const*, char const*) (global.cpp:246) 
==23168== by 0x82DEA23: addTable (helper.cpp:93) 
==23168== by 0x810DE1F: query_table_expression (OracleSQLParser.c:165181) 
==23168== by 0x8108F66: table_reference (OracleSQLParser.c:162767) 
==23168== by 0x81154B1: join_clause (OracleSQLParser.c:168172) 
==23168== by 0x82A0845: synpred349_OracleSQL_fragment (OracleSQLParser.c:460632) 
==23168== by 0x82AFA48: synpred349_OracleSQL (OracleSQLParser.c:469414) 

helper.cpp: addTable - putValue просто добавляет указатель на карту.

void addTable(char* schema, char* table) { 
    ::gbl_info->tables->putValue(::gbl_info->factory.makeColumn(schema,table,""),NULL); 
} 

GenericFactory :: makeColumn

Column* GenericFactory::makeColumn(const char* schema,const char* table, const char* column) { 
    this->count++; 
    Column* col = new Column(schema,table,column); 
    this->allocated_objects.push_back(col); 
    return col; 
} 

Колонка :: Колонка

Column::Column(const char* schema, const char* table, const char* column) { 
    string temp = schema; 
    this->schema = normalize(temp); 
    temp = table; 
    this->table = normalize(temp); 
    temp = column; 
    this->column = normalize(temp); 
    temp = schema; 
    temp = temp + "." + table + "." + column; 
    this->text = normalize(temp); 
} 

нормализуют

string& normalize(string& str) { 
    for (string::iterator p=str.begin(); p != str.end(); p++) 
     *p = toupper(*p); 
    str.erase(remove(str.begin(),str.end(),'"'),str.end()); // erase double quotes 
    return str; 
} 

определение столбца: SQLData не имеет членов или конструкторов

class Column : public SQLData { 
    std::string text; 
    std::string schema; 
    std::string table; 
    std::string column; 
public: 
    std::string alias; // TABLE alias 
    Column(const char*,const char*,const char*); 
    Column(const std::string qn); 
    //Has functions too, but probably irrelevant 
} 

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

+0

Как вы определяете, что у вас есть утечка памяти? – Doug

+0

@Doug Размер процесса достигает примерно 400 МБ после обработки 20 000 предметов ... он должен обрабатывать миллионы и продолжает расти. Поэтому я побежал к Вальгринду, чтобы найти их. Между каждым элементом нет совместного доступа - вся память должна быть удалена между ними, поэтому след памяти процесса должен быть относительно небольшим. – shaddow

+0

В моем опыте с C++ почти каждый случай «утечки памяти» был вызван «новым», который не был сопряжен с «delete». Вы вызываете 'makeColumn()' для каждого обрабатываемого элемента? – Doug

ответ

4

Отличный способ решения таких проблем, как этот (ошибки неизвестного происхождения), попробуйте загрузить GCC и выбросить код с 'the Wall'.

+0

Спасибо! См. Мое сообщение ниже для объяснения ошибки, которая была обнаружена (для потенциальных будущих читателей). – shaddow

2

Хорошо, поэтому я понял. Проблема возникла, когда я запустил ее с помощью -Wall, поэтому я согласен с этим ответом :) Вот в чем проблема.

Виртуальные деструкторы. Не знакомый с C++, я только вчера слышал о них ... Я не думал, что мне нужно его использовать, поскольку на моих производных классах у меня нет кода очистки. ЛОЖНЫЙ! Для того, чтобы даже деструктор по умолчанию вызывался на производных классах, деструктор для суперкласса (в данном случае SQLData) должен быть объявлен виртуальным. Таким образом, члены строки не очищались в моих производных классах, хотя они не были указателями.

Интересно, что я бы не рекомендовал Cygwin для отладки. Параметр -Wall НЕ предупреждал меня об этом на gcc Cygwin, но когда я скомпилировал его на машине Ubuntu, он рассказал мне для каждого класса.

Таким образом, все, что я сделал, чтобы исправить эту массивную утечку памяти было добавить следующее к моему Sqldata определения класса:

virtual ~SQLData() { } 

бац, исправлено. Мне не нужно было объявлять деструкторы объявления для любого из моих производных классов.

Спасибо за помощь!

+0

Рад, что вы разобрались! :) – Monkeyanator

Смежные вопросы