简体   繁体   中英

Memory leak on object destruction

I have a toy project which is a game engine. It uses SDL2 and C++11. In the code below I tried to make an objects which cleans memory after itself in destructor. But something goes wrong and some memory leaks. What am I doing wrong?

Example is minimal working code which triggers a leak. I suppose it works like this: Instance of class Game upon costruction creates instances of SDLEngine and Graphics (in this order), both of which allocates some memory too. When game object is destroyed it calls destructors of Graphics and SDLEngine (in this order). If I add some printing in both of this destructors they are printed in the needed order. But valgrind thinks that memory allocated by SDL_Init() and SDL_CreateWindow() are leaked.

Edit: it is probably valgrind behaviour. I saw a similar question and similar warnings in the pretty basic SDL example: Why does valgrind say basic SDL program is leaking memory?

src/leak-test.cpp:

#include <SDL2/SDL.h>
#include <stdexcept>

class SDLEngine {
public:
    SDLEngine() {
        if (SDL_Init(SDL_INIT_VIDEO) != 0) {
            throw std::runtime_error("SDL_Init"); // line 7
        }
        if (SDL_ShowCursor(SDL_DISABLE) < 0) {
            throw std::runtime_error("SDL_ShowCursor");
        }
    }
    ~SDLEngine() {
        SDL_Quit();
    }
};

class Graphics {
public:
    Graphics() :
        sdlWindow{SDL_CreateWindow(
                    "LeakTest",
                    SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                    320, 240,
                    0
                    )} // line 27
    {
        if (sdlWindow == nullptr) {
            throw std::runtime_error("SDL_CreateWindow");
        }
    }
    ~Graphics() {
        SDL_DestroyWindow(sdlWindow);
    }
    Graphics(const Graphics&)=delete;
    Graphics& operator=(const Graphics&)=delete;
private:
    SDL_Window *sdlWindow;
};

class Game {
public:
    Game() :
        sdlEngine_(),
        graphics_() // line 46
    {
        SDL_Event event;
        bool running{true};
        while (running) {
            while (SDL_PollEvent(&event)) {
                switch (event.type) {
                case SDL_KEYDOWN:
                    running = false;
                    break;
                default:
                    break;
                }
            }
        }

    }
    ~Game() {}
private:
    const SDLEngine sdlEngine_;
    Graphics graphics_;
};

int main() {
    Game game; // line 70
    return 0;
}

Makefile:

CXX := g++
MKDIR := mkdir -p
CXXFLAGS += `pkg-config --cflags sdl2 SDL2_image`
CXXFLAGS += -Wall -Werror -Wextra -Weffc++ -pedantic -std=c++0x -g
LDFLAGS += `pkg-config --libs sdl2 SDL2_image`
PROG := bin/leak-test
OBJS := $(patsubst src/%.cpp,obj/%.o, $(wildcard src\/*.cpp))
#                         escaped to fool SO parser ^
.PHONY: all clean

all: build

build: $(PROG)

clean:
    rm -rf $(PROG) $(OBJS)

$(PROG): obj/leak-test.o

$(PROG):
    @$(MKDIR) $(dir $@)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $^

obj/%.o : src/%.cpp
    @$(MKDIR) $(dir $@)
    $(CXX) $(CXXFLAGS) -c -MD -o $@ $<

Valgrind output:

host:cave-test » valgrind --leak-check=full ./bin/leak-test 
==28815== Memcheck, a memory error detector
==28815== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==28815== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==28815== Command: ./bin/leak-test
==28815== 
==28815== 
==28815== HEAP SUMMARY:
==28815==     in use at exit: 66,235 bytes in 506 blocks
==28815==   total heap usage: 19,844 allocs, 19,338 frees, 44,931,400 bytes allocated
==28815== 
==28815== 20 bytes in 2 blocks are definitely lost in loss record 7 of 101
==28815==    at 0x4C274A0: malloc (vg_replace_malloc.c:291)
==28815==    by 0x5BF8829: strdup (strdup.c:42)
==28815==    by 0x7203666: ??? (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815==    by 0x7204474: _XimSetICValueData (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815==    by 0x71FFA69: _XimLocalCreateIC (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815==    by 0x71E6044: XCreateIC (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815==    by 0x5111CD2: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x51120F7: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x51055FF: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x510540F: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x507048E: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x400D6E: SDLEngine::SDLEngine() (leak-test.cpp:7)
==28815== 
==28815== 20 bytes in 2 blocks are definitely lost in loss record 8 of 101
==28815==    at 0x4C274A0: malloc (vg_replace_malloc.c:291)
==28815==    by 0x5BF8829: strdup (strdup.c:42)
==28815==    by 0x7203666: ??? (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815==    by 0x7204474: _XimSetICValueData (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815==    by 0x71FFA69: _XimLocalCreateIC (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815==    by 0x71E6044: XCreateIC (in /usr/lib/x86_64-linux-gnu/libX11.so.6.3.0)
==28815==    by 0x5111CD2: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x51120F7: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x51055FF: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x400F11: Graphics::Graphics() (leak-test.cpp:27)
==28815==    by 0x401012: Game::Game() (leak-test.cpp:46)
==28815==    by 0x400D31: main (leak-test.cpp:70)
==28815== 
==28815== 104 bytes in 1 blocks are definitely lost in loss record 60 of 101
==28815==    at 0x4C274A0: malloc (vg_replace_malloc.c:291)
==28815==    by 0xD330A11: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==28815==    by 0xD309600: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==28815==    by 0xD305E7A: ??? (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==28815==    by 0xD30660F: glXChooseVisual (in /usr/lib/mesa-diverted/x86_64-linux-gnu/libGL.so.1.2.0)
==28815==    by 0x510ED0E: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x510EF40: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x5103B65: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x51056FB: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x510540F: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x507048E: ??? (in /usr/lib/x86_64-linux-gnu/libSDL2-2.0.so.0.2.0)
==28815==    by 0x400D6E: SDLEngine::SDLEngine() (leak-test.cpp:7)
==28815== 
==28815== LEAK SUMMARY:
==28815==    definitely lost: 144 bytes in 5 blocks
==28815==    indirectly lost: 0 bytes in 0 blocks
==28815==      possibly lost: 0 bytes in 0 blocks
==28815==    still reachable: 66,091 bytes in 501 blocks
==28815==         suppressed: 0 bytes in 0 blocks
==28815== Reachable blocks (those to which a pointer was found) are not shown.
==28815== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==28815== 
==28815== For counts of detected and suppressed errors, rerun with: -v
==28815== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 7 from 3)

It turns out this leak belongs to layer under SDL, in the X11 library. This bug is very old and known by SDL devs. See this bugzilla thread: https://bugzilla.libsdl.org/show_bug.cgi?id=2086

I close the question now.

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