Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Help with memory leaks [Solved]  (Read 2885 times)

0 Members and 1 Guest are viewing this topic.

Ziburinis

  • Newbie
  • *
  • Posts: 15
    • View Profile
Help with memory leaks [Solved]
« on: February 14, 2018, 03:11:10 am »
UPDATE: My base class destructor wasn't virtual. If I had a dollar....

UPDATE: You may want to skip this post and look at the second one.

Hello, I've been working on a game, it's about 2000 lines long, and I just needed to use Valgrind for the first time to find a segfault. I was surprised to see significant memory leaks all over the place. The leaks are in all of my backups, so I can't figure out where it was introduced, and I haven't been able to replicate it in a toy program. I'm hoping someone here will have some insight before I go nuts stripping it down to a minimum example. I've posted most of a Valgrind output here:
https://paste.debian.net/1010180/

I'm not using any dynamic memory allocation other than STL containers (no new or malloc). I use unique pointers for ownership and raw pointers elsewhere, but I can't think of any way they could be causing this. I'm also not doing anything weird with function pointers, or objects deleting themselves in weird ways, or anything like that.

I know that this looks like a false positive, since there's a lot from the graphics driver in there, but when I monitor the process's memory usage it seems to go up as I play the game, when no additional memory should be allocated.

It's also strange because if I don't call reserve on my vector<Text> of menu items then this block:
Code: [Select]
==30033== 29,784 (3,520 direct, 26,264 indirect) bytes in 1 blocks are definitely lost in loss record 2,038 of 2,053
==30033==    at 0x4C2D1FF: operator new(unsigned long) (vg_replace_malloc.c:334)
==30033==    by 0x138365: __gnu_cxx::new_allocator<sf::Text>::allocate(unsigned long, void const*) (new_allocator.h:111)
==30033==    by 0x1382AF: std::allocator_traits<std::allocator<sf::Text> >::allocate(std::allocator<sf::Text>&, unsigned long) (alloc_traits.h:436)
==30033==    by 0x137F77: std::_Vector_base<sf::Text, std::allocator<sf::Text> >::_M_allocate(unsigned long) (stl_vector.h:172)
==30033==    by 0x137B6D: sf::Text* std::vector<sf::Text, std::allocator<sf::Text> >::_M_allocate_and_copy<sf::Text const*>(unsigned long, sf::Text const*, sf::Text const*) (stl_vector.h:1260)
==30033==    by 0x1378B0: std::vector<sf::Text, std::allocator<sf::Text> >::reserve(unsigned long) (vector.tcc:73)
==30033==    by 0x136FBB: GameCore::Menu::init(sf::RenderWindow&) (menu.cpp:20)
==30033==    by 0x112C45: GameCore::DialogMenu::init(sf::RenderWindow&, unsigned short) (dialog_menu.cpp:20)
==30033==    by 0x12DD5D: GameCore::DialogState::init() (dialog_state.cpp:8)
==30033==    by 0x12E3C3: GameCore::App::pushState(GameCore::GameStateEnum, unsigned short) (app.cpp:75)
==30033==    by 0x12DFDA: GameCore::App::App() (app.cpp:23)
==30033==    by 0x13901B: main (main.cpp:6)

is replaced with this block:

Code: [Select]
==3732== 27,672 (1,408 direct, 26,264 indirect) bytes in 1 blocks are definitely lost in loss record 2,039 of 2,055
==3732==    at 0x4C2D1FF: operator new(unsigned long) (vg_replace_malloc.c:334)
==3732==    by 0x1380C5: __gnu_cxx::new_allocator<sf::Text>::allocate(unsigned long, void const*) (new_allocator.h:111)
==3732==    by 0x137FD9: std::allocator_traits<std::allocator<sf::Text> >::allocate(std::allocator<sf::Text>&, unsigned long) (alloc_traits.h:436)
==3732==    by 0x137E7D: std::_Vector_base<sf::Text, std::allocator<sf::Text> >::_M_allocate(unsigned long) (stl_vector.h:172)
==3732==    by 0x137A06: void std::vector<sf::Text, std::allocator<sf::Text> >::_M_realloc_insert<>(__gnu_cxx::__normal_iterator<sf::Text*, std::vector<sf::Text, std::allocator<sf::Text> > >) (vector.tcc:406)
==3732==    by 0x1378FE: sf::Text& std::vector<sf::Text, std::allocator<sf::Text> >::emplace_back<>() (vector.tcc:105)
==3732==    by 0x137636: GameCore::Menu::addItem(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) (menu.cpp:96)
==3732==    by 0x11314A: GameCore::DialogMenu::generateItems(unsigned short) (dialog_menu.cpp:70)
==3732==    by 0x112E0D: GameCore::DialogMenu::init(sf::RenderWindow&, unsigned short) (dialog_menu.cpp:32)
==3732==    by 0x12DD5D: GameCore::DialogState::init() (dialog_state.cpp:8)
==3732==    by 0x12E3C3: GameCore::App::pushState(GameCore::GameStateEnum, unsigned short) (app.cpp:75)
==3732==    by 0x12DFDA: GameCore::App::App() (app.cpp:23)

Which originates from a fairly innocent looking function:

  void Menu::addItem(String &str) {
    sf::Text &text = m_items.emplace_back();
    text.setFont(SFML_assets::noto_mono);
    text.setString(str);
    text.setCharacterSize(SFML_assets::font_size);
    text.setFillColor( m_text_color );
    m_last_visible = min(m_items.size(), m_num_visible);
  }
 

And if I re-enable the rest of my code I also get leaks coming from Text::getGlobalBounds(), my vertex array, and elsewhere.

I wouldn't worry about it, but when all of the code is enabled it's leaking 260 kb of memory, and I plan to make it a larger idle game, which people might leave running for long periods of time. Can you think of anything dumb I could be doing, or could it be a false positive?

Sorry for being so long winded, any advice is appreciated!
« Last Edit: February 14, 2018, 05:51:54 am by Ziburinis »

Ziburinis

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: Help with memory leaks
« Reply #1 on: February 14, 2018, 05:23:26 am »
Sorry, looks like I gave up a little too fast. I think I don't understand something about unique pointers. When I start the application with this code:
auto ptr = make_unique<DialogState>(this, k_Intro);

// Game Loop
while (window.isOpen()){
  ptr->handleTick();
  ...
  ptr->draw();
}
 
There are no memory leaks! But when I do the same thing with a vector:

vector<unique_ptr<GameState>> states;
states.emplace_back(make_unique<DialogState>(this, k_Intro));

// Game loop
while (window.isOpen()){
  states.back()->handleTick();
  ...
  states.back()->draw();
}
 

I get the leaks shown in the previous post. Am I doing something wrong here? The states vector is actually a member variable, but it should still go out of scope when the program ends.
« Last Edit: February 14, 2018, 05:27:48 am by Ziburinis »

Ziburinis

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: Help with memory leaks [Solved]
« Reply #2 on: February 14, 2018, 05:54:18 am »
I think I fixed it, I forgot to make my base class destructor virtual. Déjà vu!

Thanks to anyone who read.

Really wish the GCC folks would make the delete-non-virtual-dtor warning come up more often for the sake of my sanity.
« Last Edit: February 14, 2018, 06:33:45 am by Ziburinis »