Wyciek pamięci - jak to rozumieć

0

Mam pewien projekt i wycieka gdzieś w nim pamięć... ale nie mogę zlokalizować miejsca gdzie.
Na dodatek dzieją się dziwne rzeczy przy pierwszych parunastu iteracjach - o co chodzi, że wtedy zużycie pamięci wzrasta, a potem już to się nie dzieje?
CLion, OSX El Capitan.

Parę słów o programie - na potrzeby testów menu przerobiłem do formy

void showMenu(void)
{
    Graph_t *graph;
    for(int i = 0; i < 100; ++i)
    {
        graph = graphCreation();
        updateDataBaseFile(graph);
        removeGraph(graph);
    }
}

Następnie szedłem debugerem krok po kroku i co iterację sprawdzałem ilość zajętego ramu w menedżerze. Uzyskałem takie wyniki (co iterację, w KB):

576 628 644 648 656 656 656 ... 10 kolejnych iteracji ... 664 ... 20 kolejnych iteracji ... 664 ... 20 kolejnych ... 664

To co mnie zastanawia, to fakt, czemu przez pierwsze ~15 iteracji był wyciek pamięci, a potem już nie.
Po uruchomieniu normalnie i większej ilości iteracji:
http://prnt.sc/b4wcb9
http://prnt.sc/b4wcgs

Jak widać potem wycieku nie ma.
Sprawdzając funkcje odpowiadające za usuwanie dynamicznych obiektów z pamięci, również nic nie znalazłem.

Z kolei wykorzystując narzędzie Valingrad dla 100 iteracji, otrzymałem następujący wynik:

==38912== HEAP SUMMARY:
==38912== in use at exit: 22,451 bytes in 188 blocks
==38912== total heap usage: 50,268 allocs, 50,080 frees, 2,433,819 bytes allocated
==38912==
==38912== Searching for pointers to 188 not-freed blocks
==38912== Checked 9,805,504 bytes

Oraz pewne wycieki pamięci:

==38912== 513 bytes in 1 blocks are definitely lost in loss record 52 of 62
==38912== at 0x100010D81: malloc (vg_replace_malloc.c:303)
==38912== by 0x1001FC66C: __parsefloat_buf (in /usr/lib/system/libsystem_c.dylib)
==38912== by 0x1001FA9EF: __svfscanf_l (in /usr/lib/system/libsystem_c.dylib)
==38912== by 0x1001EE492: fscanf (in /usr/lib/system/libsystem_c.dylib)
==38912== by 0x100002138: createLists (ListCreation.c:87)
==38912== by 0x1000017DD: graphCreation (GraphCreation.c:82)
==38912== by 0x10000177D: showMenu (Menu.c:62)
==38912== by 0x100001753: main (main.c:25)

I tip jest taki, że rzecz się dzieje przy fscanfie w funkcji createLists, która zostaje wywołana w funkcji graphCreation.
Parę słów o funkcjach - pierwsza tworzy listy, do których zostają wczytywane połączenia pomiędzy miastami z pliku (stąd się pojawia fscanf), a potem następuje powrót do graphCreation i zostają one dodane do grafu (wcześniej graf jest dynamicznie alokowany).

updateDataBaseFile aktualizuje plik z połączeniami (normalnie w programie jest menu, gdzie można edytować te połączenia).
removeGraph oczywiście usuwa cały graf z pamięci.

Co oznacza narastanie zużycia pamięci na początku? Przeglądając usuwanie grafu nie znalazłem tam żadnego błędu, a jeśli by był - to przecież rosłoby zużycie pamięci po tych 100k iteracjach.

0

Szklana kula mówi, że w linii 42 jest błąd. Bez kodu tylko kula pomoże.

Jeśli potem ilość pamięci pozostaje na tak niskim poziomie to może po prostu program nie zwrócił zaalokowanej pamięci od systemu operacyjnego? Gdy wołasz malloc(10) to malloc nie woła OSowych funkcji do alokacji pamięci, bo to zbyt wolne, tylko prosi raz o więcej a potem z tej puli daje.

0

wrzucę na wklej.org po prostu.

Plik GraphCreation.c: http://wklej.org/id/2398711/
Plik GraphRepresentasion: http://wklej.org/id/2398712/
Plik CreateLists.c: http://wklej.org/id/2398713/
Plik ListsRepresentation.h: http://wklej.org/id/2398734/
i menu:

void showMenu(void)
{
    Graph_t *graph;
    for(int i = 0; i < 100; ++i)
    {
        graph = graphCreation();
        updateDataBaseFile(graph);
        removeGraph(graph);
    }
}

Po krótce co się dzieje: w pliku DataBase.txt jest sobie spis połączeń pomiędzy miastami w formie "miasto1 miasto2 odległość", program tworzy listę connections_list gdzie dodaje te połączenia, a następnie wyszukuje unikalne miasta (tj. aby nazwy się nie powtarzały) i zapisuje je w kolejności alfabetycznej do unique_cities_list. I to potem na podstawie unique_cities_list te połączenia z connections_list są dodawane do grafu (aby zachować kolejność alfabetyczną).

0

Polecam dodać mniej więcej coś takiego:

#define myMalloc(size,desc)                _myMalloc(size, __func__ , __LINE__ , desc )
#define myFree(a,desc)                             _myFree(a,__func__,__LINE__,desc)

void * _myMalloc( size_t Size , char * Func , int Line , char * Description)
{
     // tu jakis printf albo fprintf do pliku - co ci latwiej znalezc
     printf("MALLOC-%-10s: %s:%d\n" , Description , File , Line);
     return malloc(size);
}


void  _myFree( void * p , char * Func , int Line , char * Description)
{
     // tu jakis printf albo fprintf do pliku - co ci latwiej znalezc
     printf("FREE-%-10s: %s:%d\n" , Description , File , Line);
     free(p)
}

A potem policzyc wystąpienia każdej alokacji - powinno być łatwiej znaleźć wyciek no i moze sie przydac w przyszlosci

0

hmm, udało mi się wykryć pierwszy fragment kodu, gdzie mam wyciek (a przynajmniej wg Valgrinda). Jak nie wchodzę w tę funkcję, to wycieku nie ma, jak wchodzę to

513 bytes in 1 blocks are definitely lost in loss record 49 of 59
==9661==    at 0x100010D81: malloc (vg_replace_malloc.c:303)
==9661==    by 0x1001FC66C: __parsefloat_buf (in /usr/lib/system/libsystem_c.dylib)
==9661==    by 0x1001FA9EF: __svfscanf_l (in /usr/lib/system/libsystem_c.dylib)
==9661==    by 0x1001EE492: fscanf (in /usr/lib/system/libsystem_c.dylib)
==9661==    by 0x1000022C5: createLists (ListCreation.c:87)
==9661==    by 0x10000197D: graphCreation (GraphCreation.c:82)
==9661==    by 0x10000191D: showMenu (Menu.c:62)
==9661==    by 0x1000018F3: main (main.c:25)

I zawężyłem sobie fragment funkcji:

void createLists(ConnectionsList_t *connections_list, UniqueCitiesList_t *unique_cities_list)
{
    char city1[GLOBAL_CITYS_NAME_LENGTH], city2[GLOBAL_CITYS_NAME_LENGTH];

    size_t number_of_connections = 0;
    double distance;

    int result;
    FILE *fp;

    if((fp = fopen("DataBase.txt", "r")) == NULL)
    {
        printErrorDataBase(CANT_OPEN_FILE);
        return;
    }

    while((result = fscanf(fp, "%s %s %lf\n", city1, city2, &distance)) != EOF)
    {
        fclose(fp);
        return;
	// reszta kodu, nieistotne.
     }
}

Jeśli wychodzę z funkcji przed whilem, to nie ma tego wycieku. Więc musi być coś nie tak z fscanfem. Ale co?

0

z Twojego postu wynika, że podejrzewasz, że wyciek pamięci leży po stronie systemu operacyjnego. Nie chce mi się w to wierzyć, bo by się zdarzało częściej, aczkolwiek musisz powiedzieć na jakim to OSie się dzieje

0

Według mnie jest bardziej prawdopodobne ze to tylko echo tego co się dzieje gdzie indziej. NP może być zmienna jakas nieuzupelniona lub nieuzywana przez to ze ty robisz returna. Poza tym zrobiłeś to co ci podalem? Wklejasz do notepad++ i on ci podliczy wystąpienia każdej alokacji i releasu. Nikt ci w kodzie nie będzie szukał wycieku bo nikt tego nie kubki

0

Poczytaj sobie jak działa sterta. Będziesz wiedział, dlaczego zwolnienie przydzielonej pamięci nie musi (od razu) zmniejszyć ilości zajętej pamięci przez aplikację.

1 użytkowników online, w tym zalogowanych: 0, gości: 1