Подтвердить что ты не робот

Почему 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 течет в памяти?

4b9b3361

Ответ 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

Синглтоны в значительной степени всегда являются "утечкой" со стандартными реализациями. Обычно это нормально, так как обычно это не так, как вы хотите выгрузить свою способность делать такие вещи, как печать на консоль.