Все еще достижимая утечка, обнаруженная Вальгриндом - PullRequest
136 голосов
/ 01 октября 2010

Все функции, упомянутые в этом блоке, являются библиотечными функциями. Как я могу исправить эту утечку памяти?

Он указан в категории " Все еще достижимо ". (Есть еще 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)

Catch: Как только я запустил мою программу, она не дала утечек памяти, но у нее была еще одна строка в выводе Valgrind, которой раньше не было:

Сбрасывание симов в 0x5296fa0-0x52af438 в /lib/libgcc_s-4.4.4-20100630.so.1 из-за munmap ()

Если утечка не может быть устранена, может кто-нибудь хотя бы объяснить, почему строка munmap () заставляет Valgrind сообщать о 0 «все еще достижимых» утечках?

Edit:

Вот минимальный тестовый образец:

#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 ]

332 голосов
/ 04 октября 2010

Существует более одного способа определения «утечки памяти». В частности, есть два основных определения «утечки памяти», которые широко используются программистами.

Первое обычно используемое определение «утечки памяти»: «Память была выделена и впоследствии не была освобождена до завершения программы». Тем не менее, многие программисты (справедливо) утверждают, что некоторые типы утечек памяти, которые соответствуют этому определению, на самом деле не создают никаких проблем, и поэтому не должны рассматриваться как true «утечки памяти».

Возможно, более строгое (и более полезное) определение «утечки памяти» таково: «Память была выделена, и не может быть впоследствии освобождена, поскольку у программы больше нет указателей на выделенный блок памяти». Другими словами, вы не можете освободить память, на которую у вас больше нет указателей. Следовательно, такая память является «утечкой памяти». Valgrind использует это более строгое определение термина «утечка памяти». Это тип утечки, который потенциально может привести к значительному истощению кучи, особенно для долгоживущих процессов.

Категория «все еще достижимая» в отчете об утечке Valgrind относится к выделениям, которые соответствуют только первому определению «утечки памяти». Эти блоки не были освобождены, но они могли быть освобождены (если бы программист захотел), потому что программа все еще отслеживала указатели на эти блоки памяти.

В общем, нет необходимости беспокоиться о «все еще доступных» блоках. Они не представляют собой проблему, которую могут вызвать утечки памяти true . Например, обычно нет возможности исчерпать кучу из «все еще доступных» блоков. Это связано с тем, что эти блоки обычно являются одноразовыми, ссылки на которые хранятся в течение всего времени жизни процесса. Несмотря на то, что вы могли бы пройти и убедиться, что ваша программа освобождает всю выделенную память, это обычно не дает практической пользы, поскольку операционная система в любом случае восстановит всю память процесса после его завершения. Сравните это с true утечками памяти, которые, если оставить их нефиксированными, могут привести к тому, что процессу не хватит памяти, если он останется работать достаточно долго, или просто заставят процесс использовать намного больше памяти, чем необходимо.

Вероятно, единственное время, когда полезно убедиться, что все распределения имеют совпадающие "освобождения", - это если ваши инструменты обнаружения утечек не могут определить, какие блоки "еще доступны" (но Valgrind может это сделать) или если ваша операционная система не восстановить всю память завершающего процесса (все платформы, для которых Valgrind был перенесен для этого).

10 голосов
/ 04 октября 2010

Поскольку внизу есть какая-то подпрограмма из семейства pthread (но я не знаю, какая именно), я предполагаю, что вы запустили какой-то поток как присоединяемый, который завершил выполнение.

Информация о состоянии выхода этого потока сохраняется до тех пор, пока вы не вызовете pthread_join.Таким образом, память сохраняется в записи о потерях при завершении программы, но она все еще доступна, так как вы можете использовать pthread_join для доступа к ней.

Если этот анализ верен, либо запустите эти потоки отдельно, либо присоединитесьих перед завершением вашей программы.

Edit : я запустил вашу программу-пример (после некоторых очевидных исправлений), и у меня нет ошибок, но следующее

==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, 64bit)

7 голосов
/ 03 октября 2010

Вы не понимаете, что означает still reachable.

Все, что still reachable, не утечка.Вам не нужно ничего с этим делать.

3 голосов
/ 15 мая 2018

Вот правильное объяснение «все еще достижимо»:

«Все еще достижимо» - это утечки, назначаемые глобальным и статически-локальным переменным. Поскольку 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".

0 голосов
/ 17 января 2019

Для будущих читателей «Все еще доступный» может означать, что вы забыли закрыть что-то вроде файла.Хотя в первоначальном вопросе это не так, вы всегда должны это делать.

...