Все еще достижимый утечек, обнаруженный Valgrind

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

Он указан в категории Все еще достижимая. (Есть еще 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 сообщать о "утечках", доступных до сих пор?

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

Ответ 1

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

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

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

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

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

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

Ответ 2

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

Информация о состоянии выхода этого потока сохраняется до тех пор, пока вы не вызовете 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 бит)

Ответ 3

Похоже, вы не понимаете, что означает still reachable.

Ничего still reachable не является утечкой. Вам не нужно ничего делать.

Ответ 4

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

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

Ответ 5

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