Все еще достижимая утечка, обнаруженная Вальгриндом
Все функции, упомянутые в этом блоке, являются библиотечными функциями. Как я могу исправить эту утечку памяти?
Он указан в категории "Все еще достижимо". (Есть еще 4, которые очень похожи, но разных размеров)
630 bytes in 1 blocks are still reachable in loss record 5 of 5
at 0x4004F1B: calloc (vg_replace_malloc.c:418)
by 0x931CD2: _dl_new_object (dl-object.c:52)
by 0x92DD36: _dl_map_object_from_fd (dl-load.c:972)
by 0x92EFB6: _dl_map_object (dl-load.c:2251)
by 0x939F1B: dl_open_worker (dl-open.c:255)
by 0x935965: _dl_catch_error (dl-error.c:178)
by 0x9399C5: _dl_open (dl-open.c:584)
by 0xA64E31: do_dlopen (dl-libc.c:86)
by 0x935965: _dl_catch_error (dl-error.c:178)
by 0xA64FF4: __libc_dlopen_mode (dl-libc.c:47)
by 0xAE6086: pthread_cancel_init (unwind-forcedunwind.c:53)
by 0xAE61FC: _Unwind_ForcedUnwind (unwind-forcedunwind.c:126)
Поймать: Как только я запустил мою программу, она не дала утечек памяти, но у нее была еще одна строка в выводе Valgrind, которой раньше не было:
Отказ от символов в 0x5296fa0-0x52af438 в /lib/libgcc_s-4.4.4-20100630.so.1 из-за munmap()
Если утечка не может быть устранена, может кто-нибудь хотя бы объяснить, почему строка munmap() заставляет Valgrind сообщать 0 "все еще достижимых" утечек?
Редактировать:
Вот минимальный тестовый образец:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *runner(void *param) {
/* some operations ... */
pthread_exit(NULL);
}
int n;
int main(void) {
int i;
pthread_t *threadIdArray;
n=10; /* for example */
threadIdArray = malloc((n+n-1)*sizeof(pthread_t));
for(i=0;i<(n+n-1);i++) {
if( pthread_create(&threadIdArray[i],NULL,runner,NULL) != 0 ) {
printf("Couldn't create thread %d\n",i);
exit(1);
}
}
for(i=0;i<(n+n-1);i++) {
pthread_join(threadIdArray[i],NULL);
}
free(threadIdArray);
return(0);
}
Бежать с:
valgrind -v --leak-check=full --show-reachable=yes ./a.out
5 ответов
Существует несколько способов определения "утечки памяти". В частности, есть два основных определения "утечки памяти", которые широко используются программистами.
Первое часто используемое определение "утечки памяти": "Память была выделена и впоследствии не была освобождена до завершения программы". Тем не менее, многие программисты (справедливо) утверждают, что некоторые типы утечек памяти, которые соответствуют этому определению, на самом деле не создают никаких проблем, и поэтому не должны рассматриваться как настоящие "утечки памяти".
Возможно, более строгое (и более полезное) определение "утечки памяти" таково: "Память была выделена и впоследствии не может быть освобождена, поскольку у программы больше нет указателей на выделенный блок памяти". Другими словами, вы не можете освободить память, на которую у вас больше нет указателей. Следовательно, такая память является "утечкой памяти". Valgrind использует это более строгое определение термина "утечка памяти". Это тип утечки, который потенциально может вызвать значительное истощение кучи, особенно для долгоживущих процессов.
Категория "все еще достижимая" в отчете об утечке Valgrind относится к выделениям, которые соответствуют только первому определению "утечки памяти". Эти блоки не были освобождены, но они могли быть освобождены (если бы программист захотел), потому что программа все еще отслеживала указатели на эти блоки памяти.
В общем, нет необходимости беспокоиться о "все еще доступных" блоках. Они не представляют собой проблему, которую могут вызвать истинные утечки памяти. Например, обычно нет возможности исчерпать кучу из "все еще доступных" блоков. Это связано с тем, что эти блоки обычно являются одноразовыми, ссылки на которые хранятся в течение всего времени жизни процесса. Несмотря на то, что вы могли бы пройти и убедиться, что ваша программа освобождает всю выделенную память, это обычно не дает практической пользы, поскольку операционная система в любом случае восстановит всю память процесса после его завершения. Сравните это с истинными утечками памяти, которые, если оставить их незафиксированными, могут привести к тому, что процессу не хватит памяти, если он останется работать достаточно долго, или просто заставят процесс использовать намного больше памяти, чем необходимо.
Вероятно, единственный раз, когда полезно убедиться, что все распределения имеют совпадающие "освобождения", это если ваши инструменты обнаружения утечек не могут определить, какие блоки "все еще доступны" (но Valgrind может это сделать) или если ваша операционная система не освобождает все память завершающего процесса (все платформы, для которых Valgrind был перенесен для этого).
Поскольку внизу есть какая-то подпрограмма из семейства pthread (но я не знаю, какая именно), я предполагаю, что вы запустили какой-то поток как присоединяемый, который завершил выполнение.
Информация о состоянии выхода этого потока остается доступной, пока вы не позвоните pthread_join
, Таким образом, память сохраняется в записи о потерях при завершении программы, но она все еще доступна, так как вы можете использовать pthread_join
чтобы получить к нему доступ.
Если этот анализ верен, либо запустите эти потоки отдельно, либо присоединитесь к ним до завершения вашей программы.
Изменить: я запустил вашу программу примера (после некоторых очевидных исправлений), и у меня нет ошибок, но следующее
==18933== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
--18933--
--18933-- used_suppression: 2 dl-hack3-cond-1
--18933-- used_suppression: 2 glibc-2.5.x-on-SUSE-10.2-(PPC)-2a
Так как dl-
вещь напоминает многое из того, что вы видите, я думаю, что вы видите известную проблему, которая имеет решение в виде файла подавления для valgrind
, Возможно, ваша система не обновлена, или ваш дистрибутив не поддерживает эти вещи. (Моя Ubuntu 10,4, 64-битная)
Вы, кажется, не понимаете, что still reachable
средства.
Что-нибудь still reachable
это не утечка. Вам не нужно ничего делать с этим.
Вот правильное объяснение "все еще достижимо":
"Все еще достижимы" - утечки, назначенные глобальным и статически-локальным переменным. Поскольку valgrind отслеживает глобальные и статические переменные, он может исключать выделения памяти, которые назначаются "однажды и забудь". Глобальная переменная назначала распределение один раз и никогда не переназначала, что распределение обычно не является "утечкой" в том смысле, что оно не увеличивается бесконечно. В строгом смысле это все еще утечка, но обычно ее можно игнорировать, если только вы не педантичны.
Локальные переменные, которым назначены распределения, а не free'd, почти всегда имеют утечки.
Вот пример
int foo(void)
{
static char *working_buf = NULL;
char *temp_buf;
if (!working_buf) {
working_buf = (char *) malloc(16 * 1024);
}
temp_buf = (char *) malloc(5 * 1024);
....
....
....
}
Valgrind будет сообщать о working_buf как "все еще достижимо - 16k", а temp_buf как "определенно потеряно - 5k".
Для будущих читателей "Все еще доступный" может означать, что вы забыли закрыть что-то вроде файла. Хотя в первоначальном вопросе это не так, вы всегда должны убедиться, что сделали это.