5 Stimmen

Aufruf von calloc - Speicherleck valgrind

Der folgende Code ist ein Beispiel aus der NCURSES Menü Bibliothek. Ich bin nicht sicher, was mit dem Code falsch sein könnte, aber valgrind meldet einige Probleme. Irgendwelche Ideen...

==4803== 1,049 (72 direct, 977 indirect) bytes in 1 blocks are definitely lost in loss record 25 of 36
==4803==    at 0x4C24477: calloc (vg_replace_malloc.c:418)
==4803==    by 0x400E93: main (in /home/gerardoj/a.out)
==4803== 
==4803== LEAK SUMMARY:
==4803==    definitely lost: 72 bytes in 1 blocks
==4803==    indirectly lost: 977 bytes in 10 blocks
==4803==      possibly lost: 0 bytes in 0 blocks
==4803==    still reachable: 64,942 bytes in 262 blocks

Quellcode:

#include <curses.h>
#include <menu.h>

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define CTRLD   4

char *choices[] = {
    "Choice 1",
    "Choice 2",
    "Choice 3",
    "Choice 4",
    "Choice 5",
    "Choice 6",
    "Choice 7",
    "Exit",
}
;

int main()
{
    ITEM **my_items;
    int c;
    MENU *my_menu;
    int n_choices, i;
    ITEM *cur_item;

    /* Initialize curses */
    initscr();
    cbreak();
    noecho();
    keypad(stdscr, TRUE);

    /* Initialize items */
    n_choices = ARRAY_SIZE(choices);
    my_items = (ITEM **)calloc(n_choices + 1, sizeof(ITEM *));
    for (i = 0; i < n_choices; ++i) {
        my_items[i] = new_item(choices[i], choices[i]);
    }
    my_items[n_choices] = (ITEM *)NULL;

    my_menu = new_menu((ITEM **)my_items);

    /* Make the menu multi valued */
    menu_opts_off(my_menu, O_ONEVALUE);

    mvprintw(LINES - 3, 0, "Use <SPACE> to select or unselect an item.");
    mvprintw(LINES - 2, 0, "<ENTER> to see presently selected items(F1 to Exit)");
    post_menu(my_menu);
    refresh();

    while ((c = getch()) != KEY_F(1)) {
        switch (c) {
        case KEY_DOWN:
            menu_driver(my_menu, REQ_DOWN_ITEM);
            break;
        case KEY_UP:
            menu_driver(my_menu, REQ_UP_ITEM);
            break;
        case ' ':
            menu_driver(my_menu, REQ_TOGGLE_ITEM);
            break;
        case 10:
            {
                char temp[200];
                ITEM **items;

                items = menu_items(my_menu);
                temp[0] = '\0';
                for (i = 0; i < item_count(my_menu); ++i)
                if(item_value(items[i]) == TRUE) {
                    strcat(temp, item_name(items[i]));
                    strcat(temp, " ");
                }
                move(20, 0);
                clrtoeol();
                mvprintw(20, 0, temp);
                refresh();
            }
            break;
        }
    }
    unpost_menu(menu);
    free_item(my_items[0]);
    free_item(my_items[1]);
    free_item(my_items[2]);
    free_item(my_items[3]);
    free_item(my_items[4]);
    free_item(my_items[5]);
    free_item(my_items[6]);
    free_item(my_items[7]);
    free_menu(my_menu);
    endwin();
}

4voto

Josh Kelley Punkte 52169

Nach Angaben der NCURSES-Programmierung Howto Die Verwendung der Menübibliothek erfordert folgende Schritte:

  • Flüche initialisieren
  • Erstellen Sie Elemente mit new_item(). Sie können einen Namen und eine Beschreibung für die Elemente angeben.
  • Erstellen Sie das Menü mit new_menu(), indem Sie die Elemente angeben, die angehängt werden sollen.
  • Stellen Sie das Menü mit menu_post() ein und aktualisieren Sie den Bildschirm.
  • Verarbeiten Sie die Benutzeranfragen mit einer Schleife und führen Sie die notwendigen Aktualisierungen des Menüs mit menu_driver durch.
  • Aushängen des Menüs mit menu_unpost()
  • Den von free_menu() dem Menü zugewiesenen Speicher freigeben
  • Freigeben des den Elementen zugewiesenen Speichers mit free_item()
  • Flüche beenden

Soweit ich das aus Ihrem Code erkennen kann:

  • Sie heben das Menü nicht auf (das könnte zu einem Leck führen oder einfach nur den Bildschirm verstümmeln).
  • Das Menü wird freigegeben, nachdem die Einträge freigegeben wurden (was je nach der Implementierung von ncurses ein Problem sein kann oder nicht).
  • Nur die Elemente 0 und 1 des 8-Elemente-Arrays von Elementen werden freigegeben. Dies ist wahrscheinlich ein Leck.
  • Le site my_items Array von Zeigern wird nie freigegeben. Dies ist sicherlich ein Leck.

Wie @lh3 sagte, ist das Kompilieren mit der -g kann Valgrind die Zeilennummer des verlorenen Speichers angeben.

bearbeiten (als Antwort auf Ihren Kommentar): my_items ist ein dynamisch zugewiesenes Array von Zeigern auf dynamisch erstellte Menüpunkte. Mit anderen Worten: Sie haben einen Block dynamischen Speichers, der eine Reihe von Zeigern auf eine Reihe von dynamisch zugewiesenen ncurses-Strukturen (Menüpunkte) enthält. Um also aufzuräumen, wenn Sie fertig sind, müssen Sie jede der dynamisch zugewiesenen ncurses-Strukturen freigeben, und dann müssen Sie den Speicherblock freigeben, der die Zeiger auf diese Strukturen enthielt.

Mit anderen Worten, jeder calloc o malloc braucht eine free jede new_item braucht eine free_item , und so weiter.

for (i = 0; i < n_choices; ++i) {
    free_item(my_items[i]);
}
free(my_items);

1voto

Tim Post Punkte 32750

Etwas, das man bei Valgrind beachten sollte (das kommt auf die Mailingliste für Valgrind-Benutzer oft):

still reachable: 64,942 bytes in 262 blocks

Dies ist nur ein Verweis auf Blöcke, die noch in main() beim Beenden, die (unter jedem modernen Kernel) ohnehin vom Betriebssystem zurückverlangt würde.

Es ist zwar gute Praxis, ausdrücklich free() jeder einzelne zugewiesene Block vor dem Aufruf von exit, dies ist nicht technically ausgelaufenen Speicher, da er zum Zeitpunkt des Beendens noch erreichbar war.

Konzentration auf direkte, indirekte und möglicherweise verlorene Blöcke als Josh Kelly vorgeschlagen hat. Dies ist nur eine Ergänzung zu den Antworten, die bereits auf die wahrscheinlichen Quellen der undichten Stellen hingewiesen haben.

0voto

mportiz08 Punkte 9856

Versuchen Sie vielleicht valgrind mit --leak-check=full auszuführen?

0voto

Vladimir Dyuzhev Punkte 17849
free_item(my_items[7]);
free(my_items);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X