LINUX.ORG.RU

C/C++, помогите разобраться с утечками

 , , , ,


0

2

ОС - Manjaro 15.12 (OpenRC) GTK+ - 3.18.9-1 QT - 4.8.7-7

Помогите пожалуйста разобраться с утечками. Пишу программу, хотел проверить все ли ресурсы я высвобождаю. Взял valgrind и заметил что даже GTK примеры с офф сайта показывают утечку. Вот пример с сайта GTK только без комментариев:

#include <gtk/gtk.h>

static void
print_hello (GtkWidget *widget,
             gpointer   data)
{
  g_print ("Hello World\n");
}

static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkWidget *window;
  GtkWidget *grid;
  GtkWidget *button;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Window");
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);

  grid = gtk_grid_new ();

  gtk_container_add (GTK_CONTAINER (window), grid);

  button = gtk_button_new_with_label ("Button 1");
  g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);

  gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);

  button = gtk_button_new_with_label ("Button 2");
  g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);

  gtk_grid_attach (GTK_GRID (grid), button, 1, 0, 1, 1);

  button = gtk_button_new_with_label ("Quit");
  g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);

  gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1);

  gtk_widget_show_all (window);

}

int
main (int    argc,
      char **argv)
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

И вот что выдаёт valgrind:

==24833== Memcheck, a memory error detector
==24833== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==24833== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==24833== Command: ./a.out
==24833== 

** (a.out:24833): WARNING **: Couldn't register with accessibility bus: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
==24833== 
==24833== HEAP SUMMARY:
==24833==     in use at exit: 1,609,694 bytes in 18,691 blocks
==24833==   total heap usage: 147,225 allocs, 128,534 frees, 11,600,341 bytes allocated
==24833== 
==24833== LEAK SUMMARY:
==24833==    definitely lost: 1,792 bytes in 4 blocks
==24833==    indirectly lost: 6,480 bytes in 275 blocks
==24833==      possibly lost: 4,471 bytes in 50 blocks
==24833==    still reachable: 1,493,103 bytes in 17,524 blocks
==24833==                       of which reachable via heuristic:
==24833==                         length64           : 6,512 bytes in 104 blocks
==24833==                         newarray           : 2,160 bytes in 55 blocks
==24833==         suppressed: 0 bytes in 0 blocks
==24833== Rerun with --leak-check=full to see details of leaked memory
==24833== 
==24833== For counts of detected and suppressed errors, rerun with: -v
==24833== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Если я правильно трактую вывод, то как минимум 1,792 bytes потеряны. Здесь в ответах разъясняют почему так получается, если я правильно для себя перевёл ответ, то утечки в gtk есть и будут, но это не проблема, т.к. по завершению работы вся память будет возвращена системе. Так ли это, на сколько это критично, значит ли что освобождением ресурсов в gtk программах можно вообще не озабочиваться? И есть ли хорошая альтернатива?

Аналогичная ситуация получилась с Qt:

#include <QApplication>
#include <QLabel>

int main(int argc, char **argv)
{
  QApplication app(argc, argv);
  QLabel hello("Hello world!");

  hello.show();
  return app.exec();
}

Вывод valgrind:

==25664== Memcheck, a memory error detector
==25664== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==25664== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==25664== Command: ./hello
==25664== 
==25664== 
==25664== HEAP SUMMARY:
==25664==     in use at exit: 1,719,534 bytes in 15,419 blocks
==25664==   total heap usage: 57,953 allocs, 42,534 frees, 12,142,263 bytes allocated
==25664== 
==25664== LEAK SUMMARY:
==25664==    definitely lost: 3,936 bytes in 15 blocks
==25664==    indirectly lost: 12,890 bytes in 512 blocks
==25664==      possibly lost: 4,390 bytes in 49 blocks
==25664==    still reachable: 1,446,678 bytes in 13,824 blocks
==25664==                       of which reachable via heuristic:
==25664==                         length64           : 7,064 bytes in 80 blocks
==25664==                         newarray           : 6,152 bytes in 39 blocks
==25664==         suppressed: 0 bytes in 0 blocks
==25664== Rerun with --leak-check=full to see details of leaked memory
==25664== 
==25664== For counts of detected and suppressed errors, rerun with: -v

Все эти тулкиты текучая параша. уборку другой какой-нибудь мелкой херни могут оставлять системе. Забей, если у тебя не embedded.

anonymous
()

утечки в gtk есть и будут, но это не проблема, т.к. по завершению работы вся память будет возвращена системе. Так ли это,

да

на сколько это критично,

некритично, т.к. объем утекшей памяти константен. он может зависеть еще от того, какие именно части gtk используются в программе, но постоянной растущей утечки не будет

значит ли что освобождением ресурсов в gtk программах можно вообще не озабочиваться?

нет, не значит, т.к. твоя утечка может происходить регулярно, и сожрать постепенно всю память. если же «утечка» разовая, то это и не утечка по сути, хотя valgrind ее будет детектить все равно

И есть ли хорошая альтернатива?

Qt, конечно же. но тулкит тут вообще ни при чем.

MyTrooName ★★★★★
()

После выхода из activate указателей на созданные виджеты больше нет, вот и видишь утечки.

curufinwe ★★★★★
()
Последнее исправление: curufinwe (всего исправлений: 1)
Ответ на: комментарий от MyTrooName

Но ведь Qt тоже даёт утечку, или в моём примере что-то не так?

Попробовал использовать --suppressions опцию для valgrind с файлами из https://github.com/dtrebbien/GNOME.supp, указал все supp файлы какие только есть, но результат тот же:

==27552== Memcheck, a memory error detector
==27552== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==27552== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==27552== Command: ./a.out
==27552== 

** (a.out:27552): WARNING **: Couldn't register with accessibility bus: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.
==27552== 
==27552== HEAP SUMMARY:
==27552==     in use at exit: 1,609,718 bytes in 18,691 blocks
==27552==   total heap usage: 147,147 allocs, 128,456 frees, 11,599,698 bytes allocated
==27552== 
==27552== LEAK SUMMARY:
==27552==    definitely lost: 1,792 bytes in 4 blocks
==27552==    indirectly lost: 6,480 bytes in 275 blocks
==27552==      possibly lost: 4,471 bytes in 50 blocks
==27552==    still reachable: 1,491,141 bytes in 17,480 blocks
==27552==                       of which reachable via heuristic:
==27552==                         length64           : 6,512 bytes in 104 blocks
==27552==                         newarray           : 2,160 bytes in 55 blocks
==27552==         suppressed: 1,986 bytes in 44 blocks
==27552== Rerun with --leak-check=full to see details of leaked memory
==27552== 
==27552== For counts of detected and suppressed errors, rerun with: -v
==27552== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Есть ли возможность отделить свои утечки от утечек gtk?

flyshoot
() автор топика
Ответ на: комментарий от i-rinat

G_SLICE=debug-blocks valgrind ./a.out

Получается очень длинный вывод и:

==27880== HEAP SUMMARY:
==27880==     in use at exit: 2,849,304 bytes in 18,625 blocks
==27880==   total heap usage: 149,449 allocs, 130,824 frees, 14,139,569 bytes allocated
==27880== 
==27880== LEAK SUMMARY:
==27880==    definitely lost: 12,476 bytes in 44 blocks
==27880==    indirectly lost: 6,504 bytes in 277 blocks
==27880==      possibly lost: 800,523 bytes in 2,079 blocks
==27880==    still reachable: 1,888,793 bytes in 15,922 blocks
==27880==                       of which reachable via heuristic:
==27880==                         newarray           : 1,536 bytes in 16 blocks
==27880==         suppressed: 0 bytes in 0 blocks
==27880== Rerun with --leak-check=full to see details of leaked memory
==27880== 
==27880== For counts of detected and suppressed errors, rerun with: -v
==27880== ERROR SUMMARY: 1255 errors from 119 contexts (suppressed: 0 from 0)

То есть ещё больше чем без этой опции. Или я не уловил её смысла?

flyshoot
() автор топика
Ответ на: комментарий от flyshoot

Нет, всё верно уловил. Просто от неё толку нет. Похоже, она вскрывает несколько глюков в GLib. Там решили «помочь» Valgrind'у, а он от этого ложные баги видит.

i-rinat ★★★★★
()

Просто, если какой-то объект гарантированно будет существовать все время работы проги - то можно не заморачиваться с его удалением.

RazrFalcon ★★★★★
()

Если юзаешь GTK из C++ через gtkmm, то всюду юзай виртуальные деструкторы, иначе память будет течь довольно быстро.

peregrine ★★★★★
()
Ответ на: комментарий от hizel

Если не ошибаюсь, то есть просто такая опция командной строки для valgrind, позволяет увидеть более подробную информацию по утечкам. Хотел запостить вывод в сервисы бесплатного хостинга, не влез. Поэтому скажу просто, там почти 8к строк для довольно простой программы. Не представляю как лопатить такой выхлоп для более-менее существенной программы.

flyshoot
() автор топика
Ответ на: комментарий от peregrine

Если я правильно понял, то утечка связана с запуском инфраструктуры самого GTK, в связи с чем у меня проблема отделить утечки GTK от своих, чтобы последние ликвидировать.

flyshoot
() автор топика
Ответ на: комментарий от flyshoot

GTK и Qt любят создавать всякое статическое или глобальное барахло, отсюда и «утечки».

former_anonymous ★★★
()

Можно сделать так:

1) открыл закрыл приложение, лог Валгринда сохранил.

2) Открыл, выполнил тесты, закрыл, лог Валгринда сохранил.

Теперь можно сравнить два лога, если ничего не добавилось, то в тестируемой последовательности все хорошо.

anymouse
()

Нашёл универсальный способ по созданию supp файлов для valgrind. После того как я выполнил указанную инструкцию для простенького GTK примера в своём первом сообщении, я получил файл с 2659 блоками блокировок утечек из различных библиотек так или иначе связанных с GTK. Так и должно быть или что-то не так с моей версией GTK. Почему-то это число кажется очень большим.

flyshoot
() автор топика

если это утечка


int main()
{
  int *p = new int[1024];
  return 0;
}

то я испанский лётчик. так и запиши в моём профиле

anonymous
()
Ответ на: комментарий от anonymous

Здесь я уже прочитал, что хоть приведённый пример и считается технически утечкой, по факту ею не является, т.к. создаются объекты при старте программы и уничтожаются по завершении и не плодятся при работе программы. Это я понимаю. Проблема в том, что эти «ложные срабатывания» мешают выделить реальные утечки, созданные мной. Единственный способ выделить мои утечки, это подавить «утечки» в GTK при помощи supp файлов. Что в свою очередь требует разделения GUI от всего остального перед проверкой, что сделать весьма проблематично в случаях когда суть программы в тесном взаимодействии с GUI, на мой взгляд.

flyshoot
() автор топика
Ответ на: комментарий от flyshoot

GUI всегда надо отделять от логики. Даже если пишешь в винде на C# и рисуешь окошки мышкой.

peregrine ★★★★★
()
Ответ на: комментарий от peregrine

Я использовал C и GTK+, но обнаружив эти «утечки» попробовал протестировать Qt, оттуда и C++.

flyshoot
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.