Почему valgrind говорит, что базовая программа SDL - это утечка памяти?
Вот программа SDL:
#include <SDL/SDL.h>
int main(int argc, char** argv){
SDL_Init(SDL_INIT_VIDEO);
SDL_Surface* screen = SDL_SetVideoMode(640, 480, 16, SDL_HWSURFACE);
SDL_Quit();
return 0;
}
Скомпилирован с помощью команды:
g++ -o test test.cpp -lSDL
И вот результат valgrind:
[email protected]:~/cpp/tetris$ valgrind --leak-check=full ./test
==3271== Memcheck, a memory error detector
==3271== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3271== Using Valgrind-3.5.0-Debian and LibVEX; rerun with -h for copyright info
==3271== Command: ./test
==3271==
==3271==
==3271== HEAP SUMMARY:
==3271== in use at exit: 91,097 bytes in 1,258 blocks
==3271== total heap usage: 14,250 allocs, 12,992 frees, 2,615,177 bytes allocated
==3271==
==3271== 10 bytes in 2 blocks are definitely lost in loss record 8 of 134
==3271== at 0x4024C1C: malloc (vg_replace_malloc.c:195)
==3271== by 0x4946F04: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4945DA1: _XimEncodeLocalICAttr (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4947195: _XimSetICValueData (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x493FDF1: _XimLocalCreateIC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4922478: XCreateIC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x407AA64: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x407BCBB: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x4069C2A: SDL_VideoInit (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x403F9D3: SDL_InitSubSystem (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x403FA36: SDL_Init (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x8048658: main (in /home/christian/cpp/tetris/test)
==3271==
==3271== 12 bytes in 1 blocks are definitely lost in loss record 12 of 134
==3271== at 0x4024C1C: malloc (vg_replace_malloc.c:195)
==3271== by 0x4A3DA8D: ???
==3271== by 0x4A3D48C: ???
==3271== by 0x4A3D5A4: ???
==3271== by 0x4A3DD26: ???
==3271== by 0x4A38BC5: ???
==3271== by 0x4A38FCD: ???
==3271== by 0x40717DD: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x407BDCA: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x4069C2A: SDL_VideoInit (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x403F9D3: SDL_InitSubSystem (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x403FA36: SDL_Init (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271==
==3271== 112 (8 direct, 104 indirect) bytes in 1 blocks are definitely lost in loss record 102 of 134
==3271== at 0x4024D12: realloc (vg_replace_malloc.c:476)
==3271== by 0x492847E: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492976D: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492AA41: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492B1A4: _XlcCreateLC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x494B4FA: _XlcDefaultLoader (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4933153: _XOpenLC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x49332C2: _XlcCurrentLC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4933761: XSetLocaleModifiers (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x407161D: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x407AD8F: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271== by 0x407BCBB: ??? (in /usr/lib/libSDL-1.2.so.0.11.2)
==3271==
==3271== 112 (8 direct, 104 indirect) bytes in 1 blocks are definitely lost in loss record 103 of 134
==3271== at 0x4024D12: realloc (vg_replace_malloc.c:476)
==3271== by 0x492847E: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492976D: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492AA41: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x492B1A4: _XlcCreateLC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x494B4FA: _XlcDefaultLoader (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4933153: _XOpenLC (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x493327D: _XrmInitParseInfo (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x4918F20: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x491AF37: XrmGetStringDatabase (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x48F8459: ??? (in /usr/lib/libX11.so.6.2.0)
==3271== by 0x48F864E: XGetDefault (in /usr/lib/libX11.so.6.2.0)
==3271==
==3271== LEAK SUMMARY:
==3271== definitely lost: 38 bytes in 5 blocks
==3271== indirectly lost: 208 bytes in 8 blocks
==3271== possibly lost: 0 bytes in 0 blocks
==3271== still reachable: 90,851 bytes in 1,245 blocks
==3271== suppressed: 0 bytes in 0 blocks
==3271== Reachable blocks (those to which a pointer was found) are not shown.
==3271== To see them, rerun with: --leak-check=full --show-reachable=yes
==3271==
==3271== For counts of detected and suppressed errors, rerun with: -v
==3271== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 93 from 14)
Почему эта основная программа SDL течет в памяти?
Ответы
Ответ 1
Даже для базовой программы OpenGL "hello world" без полного SDL, Valgrind дает мне подобные предупреждения глубоко внутри библиотек OpenGL. Это странно, но я предположил, что
- Разработчики библиотеки знают, что они делают (возможно, предопределяя некоторые небольшие статические буферы, которые они никогда не удосуживаются освободить),
- Даже если это не так, это одноразовая утечка, которая будет восстановлена ОС при завершении программы,
и не потеряли много сна над ним.
Ответ 2
Каждый SDL_Surface, который вы загружаете, должен быть освобожден до вызова SDL_Quit().
Для этого просто используйте SDL_FreeSurface (surfaceName), чтобы освободить поверхность, которую вы выделили в памяти.
Ответ 3
У SDL определенно есть проблема с утечкой памяти с SDL_TLSCleanup
и SDL_TLSData
.
Фактически, SDL_TLSCleanup
никогда не вызывается для основного потока.
Ответ 4
Это нормально для библиотеки графического API (OpenGL, Vulkan и т.д.) И оконного API (X11, SDL и т.д.). Этот лучший вариант - использовать файлы подавления valgrind, чтобы игнорировать эти ошибки.
Вот как это сделать с Linux, SDL & OpenGL:
Допустим, отлаживаемая программа называется prog.out (не забудьте заменить prog.out на фактическое имя вашей программы),
Вы можете экспортировать информацию о подавлении следующим образом:
valgrind --leak-check=full --show-reachable=yes --show-leak-kinds=all --error-limit=no --gen-suppressions=all --log-file=supdata.log ./prog.out
Теперь вы можете извлечь информацию о подавлении из "supdata.log", используя скрипт или вручную. Вы можете использовать подстановочные знаки ('*', '...'), чтобы сделать подавления более общими (тем самым не нужно обновлять файл подавления при каждом обновлении кода).
После этого, всякий раз, когда вы отлаживаете свою программу, вы теперь включаете файл подавления. Например, я сделал файл подавления ниже 'linux_sdl_gl.sup'. Это хорошо работает для меня при разработке с использованием SDL и OpenGL в Linux. Он игнорирует все встроенные ошибки OpenGL, SDL и X11, так что я легко могу найти ошибки, которые я создаю. Не стесняйтесь использовать его в своем развитии.
Когда я отлаживаю свой код, я использую следующий вызов valgrind. Это позволяет мне находить любые новые системные ошибки, которые мой файл подавления мог пропустить.
valgrind --gen-suppressions=all --suppressions=./linux_sdl_gl.sup --leak-check=full --show-leak-kinds=all ./prog.out
файл: linux_sdl_gl.sup
# Copyright (c) <'2019'> <'Alrick Grandison'>
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
{
opengl_memcpy_addr8
Memcheck:Addr8
fun:[email protected]*
obj:/usr/lib/x86_64-linux-gnu/dri/*_dri.so
...
}
{
opengl_memcpy_addr1
Memcheck:Addr1
fun:[email protected]*
obj:/usr/lib/x86_64-linux-gnu/dri/*_dri.so
...
}
{
opengl_memset_addr8
Memcheck:Addr8
fun:memset
obj:/usr/lib/x86_64-linux-gnu/dri/*_dri.so
...
}
{
sdl_leak_reachable
Memcheck:Leak
match-leak-kinds: reachable
...
fun:SDL_Init_REAL
...
}
{
x11_leak_reachable
Memcheck:Leak
match-leak-kinds: reachable
...
obj:/usr/lib/x86_64-linux-gnu/libX11.so.*
...
}
{
sdl_leak_indirect
Memcheck:Leak
match-leak-kinds: indirect
...
fun:SDL_Init_REAL
...
}
{
sdl_leak_definite
Memcheck:Leak
match-leak-kinds: definite
...
fun:SDL_Init_REAL
...
}
# OpenGL Calls DL under the Hood - Taken straight out of Valgrind --gen-suppressions
# Could overlap with non-graphics DL api calls
# But, If you are not using DL directly, then don't worry about this
{
dl_leak_reachable
Memcheck:Leak
match-leak-kinds: reachable
...
fun:[email protected]@GLIBC*
...
}
# Same as above but more generic
# Could overlap with non-graphics DL api calls
# But, If you are not using DL directly, then don't worry about this
{
dl_leak_reachable
Memcheck:Leak
match-leak-kinds: reachable
...
fun:_dl_*
...
}
{
x11_leak_indirect
Memcheck:Leak
match-leak-kinds: indirect
...
obj:/usr/lib/x86_64-linux-gnu/libX11.so.*
...
}
{
x11_leak_definite
Memcheck:Leak
match-leak-kinds: definite
...
obj:/usr/lib/x86_64-linux-gnu/libX11.so.*
...
}
{
x11_leak_possible
Memcheck:Leak
match-leak-kinds: possible
...
obj:/usr/lib/x86_64-linux-gnu/libX11.so.*
...
}
{
opengl_leak_reachable
Memcheck:Leak
match-leak-kinds: reachable
...
obj:/usr/lib/x86_64-linux-gnu/libGLX.so.*
...
}
github: код подавления valgrind
Ответ 5
Синглтоны в значительной степени всегда являются "утечкой" со стандартными реализациями. Обычно это нормально, так как обычно это не так, как вы хотите выгрузить свою способность делать такие вещи, как печать на консоль.