简体   繁体   中英

Can't find memory leak detected by Valgrind

I'm working on a program and I have a memory leak that I just can't nail down. I'm not very experienced with C/C++ either. I'll post ONE of the valgrind errors and class definitions and functions that are relevant... if I forget something, just ask and I will update :) The reason I am not posting all of the valgrind report is there are a lot of them, but they are similar... the only difference is the stack trace it has.

I started out designing it rather poorly, so to fix the memory leaks, my idea was to create a global factory to add my objects to in order to delete them later. I replaced every occurrence of "new" with the factory method to create it.. in this case, it is the class Column. I'm positive that every object created by makeColumn is deleted, as I use a vector to store the pointer. The function to iterate through the vector and delete each item in it IS being called before the program ends.

This valgrind report makes me think that somehow, a string is not being unallocated. I set the GLIBCXX_FORCE_NEW variable, and it makes no difference in the leaks detected. I am using gcc 4.7.2.

Also, yes, I am receiving information from an ANTLR generated parser... that probably does not matter, as ANTLR handles it's own memory. The char pointers are the only data from 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 just adds the pointer to a map.

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

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);
}

normalize

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;
}

Column definition: SQLData has no members or constructors

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
}

I've spent hours trying to fix this and I'm just not sure where I'm losing memory... the program can run for minutes or even hours while processing data, and so it really builds up.

解决此类问题(未知来源的错误)的一种好方法,请尝试下载GCC,然后将代码扔到“ ”上。

Okay, so I figured it out. The issue showed up when I ran it with -Wall, so I will accept that answer :) Here is what the issue was though.

Virtual Destructors. Not being familiar with C++, I only heard about them yesterday... I did not think I needed to use one, as I don't actually have any cleanup code in my derived classes. FALSE! In order for even the default destructor to be called on the derived classes, the destructor for the superclass (in this case SQLData) must be declared virtual. As such, the string members were not being cleaned up in my derived classes, even though they were not pointers.

Interestingly, I would not recommend Cygwin for debugging. The -Wall option did NOT warn me about it on the gcc Cygwin installed, but when I compiled on a Ubuntu machine, it told me for each class.

So, all I did to fix this massive memory leak was add the following to my SQLData class definition:

virtual ~SQLData() { }

bam, fixed. I did not need to declare declare destructors for any of my derived classes.

Thanks for the help!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM