Wszystkie funkcje wymienione w tym bloku są funkcjami bibliotecznymi. Jak mogę naprawić ten wyciek pamięci?
Znajduje się w kategorii „ Nadal osiągalne ”. (Są jeszcze 4, które są bardzo podobne, ale o różnych rozmiarach)
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: Kiedy uruchomiłem mój program, nie powodował wycieków pamięci, ale miał jedną dodatkową linię na wyjściu Valgrind, której wcześniej nie było:
Odrzucanie symboli pod adresem 0x5296fa0-0x52af438 w /lib/libgcc_s-4.4.4-20100630.so.1 z powodu munmap ()
Jeśli wycieku nie można naprawić, czy ktoś może przynajmniej wyjaśnić, dlaczego wiersz munmap () powoduje, że Valgrind zgłasza 0 przecieków „nadal osiągalnych”?
Edytować:
Oto minimalna próbka testowa:
#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);
}
Biegnij z:
valgrind -v --leak-check=full --show-reachable=yes ./a.out
Odpowiedzi:
Istnieje więcej niż jeden sposób zdefiniowania „wycieku pamięci”. W szczególności istnieją dwie podstawowe definicje „wycieku pamięci”, które są powszechnie używane przez programistów.
Pierwsza powszechnie stosowana definicja „wycieku pamięci” brzmi: „Pamięć została przydzielona i nie została następnie zwolniona przed zakończeniem programu”. Jednak wielu programistów (słusznie) twierdzi, że pewne typy wycieków pamięci, które pasują do tej definicji, w rzeczywistości nie stanowią żadnego problemu i dlatego nie powinny być uważane za prawdziwe „wycieki pamięci”.
Prawdopodobnie bardziej rygorystyczna (i bardziej użyteczna) definicja „wycieku pamięci” brzmi: „Pamięć została przydzielona i nie można jej później zwolnić, ponieważ program nie ma już żadnych wskaźników do przydzielonego bloku pamięci”. Innymi słowy, nie możesz zwolnić pamięci, do której nie masz już żadnych wskazówek. Taka pamięć jest zatem „wyciekiem pamięci”. Valgrind używa ściślejszej definicji terminu „wyciek pamięci”. Jest to rodzaj wycieku, który może potencjalnie spowodować znaczne zubożenie hałdy, szczególnie w przypadku długotrwałych procesów.
Kategoria „nadal osiągalne” w raporcie przecieków Valgrind odnosi się do przydziałów, które pasują tylko do pierwszej definicji „wycieku pamięci”. Bloki te nie zostały zwolnione, ale mogły zostać zwolnione (jeśli programista chciał), ponieważ program nadal śledził wskaźniki do tych bloków pamięci.
Ogólnie rzecz biorąc, nie ma potrzeby martwić się o „wciąż dostępne” bloki. Nie stanowią problemu, który mogą powodować prawdziwe wycieki pamięci. Na przykład normalnie nie ma możliwości wyczerpania sterty przez „wciąż osiągalne” bloki. Dzieje się tak, ponieważ bloki te są zwykle jednorazowymi alokacjami, do których odniesienia są przechowywane przez cały czas trwania procesu. Chociaż możesz przejść przez to i upewnić się, że program zwolni całą przydzieloną pamięć, zwykle nie ma to praktycznej korzyści, ponieważ system operacyjny i tak odzyska całą pamięć procesu po zakończeniu procesu. Porównaj to z prawdą przecieki pamięci, które pozostawione nienaprawione mogą spowodować, że procesowi zabraknie pamięci, jeśli będzie działał wystarczająco długo, lub po prostu spowodują, że proces zużyje znacznie więcej pamięci niż jest to konieczne.
Prawdopodobnie jedyny moment, w którym warto upewnić się, że wszystkie alokacje mają pasujące „zwolnienia”, to sytuacja, gdy narzędzia do wykrywania wycieków nie mogą określić, które bloki są „nadal osiągalne” (ale Valgrind może to zrobić) lub jeśli system operacyjny nie odzyskuje wszystkich pamięć procesu kończącego (wszystkie platformy, na które przeportował Valgrind).
źródło
munmap
jest wywoływany w wyniku wyładowania udostępnionego obiektu. Wszystkie zasoby używane przez obiekt współdzielony mogą zostać zwolnione, zanim zostanie wyładowany. To może wyjaśniać, dlaczego „nadal osiągalne” są zwalniane w tejmunmap
sprawie. Jednak tylko spekuluję. Nie ma tu wystarczających informacji, aby z pewnością powiedzieć.Ponieważ na dole znajduje się procedura z rodziny pthread (ale nie znam tej konkretnej), przypuszczam, że uruchomiłeś wątek jako łączony, który zakończył wykonywanie.
Informacje o stanie wyjścia tego wątku są dostępne do momentu wywołania
pthread_join
. W ten sposób pamięć jest przechowywana w rekordzie utraty po zakończeniu programu, ale nadal jest dostępna, ponieważ można ją wykorzystać,pthread_join
aby uzyskać do niej dostęp.Jeśli ta analiza jest prawidłowa, uruchom te wątki odłączone lub dołącz do nich przed zakończeniem programu.
Edycja : uruchomiłem twój przykładowy program (po kilku oczywistych poprawkach) i nie mam błędów, ale następujące
Ponieważ
dl-
rzecz przypomina wiele z tego, co widzisz, myślę, że widzisz znany problem, który ma rozwiązanie w postaci pliku tłumieniavalgrind
. Być może Twój system nie jest aktualny lub Twoja dystrybucja nie obsługuje tych rzeczy. (Mój to ubuntu 10.4, 64-bitowy)źródło
Wydaje się, że nie rozumiesz, co
still reachable
to znaczy.Wszystko
still reachable
to nie wyciek. Nie musisz nic z tym robić.źródło
FILE
wskazówkach?Oto prawidłowe wyjaśnienie terminu „nadal osiągalny”:
„Wciąż osiągalne” to przecieki przypisane do zmiennych globalnych i statyczno-lokalnych. Ponieważ valgrind śledzi zmienne globalne i statyczne, może wykluczyć alokacje pamięci, które są przypisane „raz i zapomnij”. Zmienna globalna, która raz przypisała alokację i nigdy jej nie zmieniała, zazwyczaj nie jest „wyciekiem” w tym sensie, że nie rośnie w nieskończoność. Nadal jest to przeciek w ścisłym tego słowa znaczeniu, ale zwykle można go zignorować, chyba że jesteś pedantyczny.
Zmienne lokalne, którym przypisano alokacje i które nie są wolne, są prawie zawsze przeciekami.
Oto przykład
Valgrind zgłosi working_buf jako „nadal osiągalny - 16k”, a temp_buf jako „zdecydowanie utracony - 5k”.
źródło
Dla przyszłych czytelników „Ciągle osiągalny” może oznaczać, że zapomniałeś zamknąć coś takiego jak plik. Chociaż nie wydaje się to w pierwotnym pytaniu, zawsze powinieneś się upewnić, że to zrobiłeś.
źródło