Noch erreichbares Leck von Valgrind entdeckt

Lesezeit: 6 Minuten

Alle in diesem Block erwähnten Funktionen sind Bibliotheksfunktionen. Wie kann ich dieses Speicherleck beheben?

Es ist unter „Immer noch erreichbar” Kategorie. (Es gibt 4 weitere, die sehr ähnlich sind, aber unterschiedliche Größen haben)

 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)

Fang: Nachdem ich mein Programm ausgeführt hatte, gab es keine Speicherlecks, aber es hatte eine zusätzliche Zeile in der Valgrind-Ausgabe, die vorher nicht vorhanden war:

Verwerfen von Syms bei 0x5296fa0-0x52af438 in /lib/libgcc_s-4.4.4-20100630.so.1 aufgrund von munmap()

Wenn das Leck nicht behoben werden kann, kann jemand zumindest erklären, warum die Zeile munmap () Valgrind dazu veranlasst, 0 “noch erreichbare” Lecks zu melden?

Bearbeiten:

Hier ist ein minimales Testbeispiel:

#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);
}

Laufen mit:

valgrind -v --leak-check=full --show-reachable=yes ./a.out

Es gibt mehr als eine Möglichkeit, “Speicherleck” zu definieren. Insbesondere gibt es zwei primäre Definitionen von “Speicherlecks”, die unter Programmierern allgemein verwendet werden.

Die erste häufig verwendete Definition von “Speicherleck” lautet: “Speicher wurde zugewiesen und anschließend nicht freigegeben, bevor das Programm beendet wurde.” Viele Programmierer argumentieren jedoch (zu Recht), dass bestimmte Arten von Speicherlecks, die dieser Definition entsprechen, eigentlich kein Problem darstellen und daher nicht berücksichtigt werden sollten Stimmt „Erinnerungsverluste“.

Eine wohl strengere (und nützlichere) Definition von „Speicherleck“ lautet: „Speicher wurde zugewiesen und kann nicht nachträglich freigegeben werden, weil das Programm keine Zeiger mehr auf den zugewiesenen Speicherblock hat.“ Mit anderen Worten, Sie können keinen Speicher freigeben, auf den Sie keine Zeiger mehr haben. Solcher Speicher ist daher ein „Speicherleck“. Valgrind verwendet diese strengere Definition des Begriffs “Speicherleck”. Dies ist die Art von Leck, die möglicherweise eine erhebliche Heap-Erschöpfung verursachen kann, insbesondere bei langlebigen Prozessen.

Die Kategorie „immer noch erreichbar“ in Valgrinds Leckbericht bezieht sich auf Zuordnungen, die nur der ersten Definition von „Speicherleck“ entsprechen. Diese Blöcke wurden nicht freigegeben, aber sie hätten freigegeben werden können (wenn der Programmierer gewollt hätte), weil das Programm immer noch Zeiger auf diese Speicherblöcke verfolgte.

Generell muss man sich um „noch erreichbare“ Blöcke keine Gedanken machen. Sie stellen nicht die Art von Problem dar Stimmt Speicherlecks können dazu führen. Zum Beispiel gibt es normalerweise kein Potenzial für Heap-Erschöpfung von “noch erreichbaren” Blöcken. Dies liegt daran, dass es sich bei diesen Blöcken normalerweise um einmalige Zuweisungen handelt, auf die während der gesamten Lebensdauer des Prozesses verwiesen wird. Sie könnten zwar durchgehen und sicherstellen, dass Ihr Programm frei wird alle zugewiesenen Speicher, hat dies normalerweise keinen praktischen Nutzen, da das Betriebssystem ohnehin den gesamten Speicher des Prozesses zurückfordert, nachdem der Prozess beendet wurde. Vergleichen Sie dies mit Stimmt Speicherlecks, die, wenn sie nicht behoben werden, dazu führen können, dass einem Prozess nicht mehr genügend Speicher zur Verfügung steht, wenn er lange genug läuft, oder einfach dazu führen, dass ein Prozess weit mehr Speicher als nötig verbraucht.

Wahrscheinlich ist es nur dann sinnvoll, sicherzustellen, dass alle Zuweisungen übereinstimmende “Freigaben” haben, wenn Ihre Lecksuchwerkzeuge nicht erkennen können, welche Blöcke “noch erreichbar” sind (aber Valgrind kann dies tun) oder wenn Ihr Betriebssystem nicht alle zurückfordert Speicher eines beendenden Prozesses (alle Plattformen, für die Valgrind portiert wurde, um dies zu tun).

  • Können Sie vermuten, was munmap() tut, das die “noch erreichbaren” Blöcke verschwinden lässt?

    Benutzer191776

    4. Oktober 2010 um 18:38 Uhr


  • @crypto: Das könnte sein munmap wird als Ergebnis des Entladens eines gemeinsam genutzten Objekts aufgerufen. Und alle vom gemeinsam genutzten Objekt verwendeten Ressourcen werden möglicherweise freigegeben, bevor es entladen wird. Dies könnte erklären, warum die „noch erreichbaren“ in der befreit werden munmap Fall. Ich spekuliere hier aber nur. Es gibt hier nicht genug Informationen, um es mit Sicherheit zu sagen.

    – Dan Formen

    4. Oktober 2010 um 19:11 Uhr

  • Ein Fall, in dem “noch erreichbarer” Speicher als Speicherleck angesehen werden kann: Nehmen Sie an, Sie haben eine Hash-Tabelle, in der Sie Zeiger auf Heap-zugewiesenen Speicher als Wert hinzufügen. Wenn Sie ständig neue Einträge in die Tabelle einfügen, aber die nicht mehr benötigten nicht entfernen und freigeben, kann sie auf unbestimmte Zeit wachsen und Heap-Speicherereignisse verlieren, wenn dieser Speicher thenisch “noch erreichbar” ist. Dies ist der Fall eines Speicherlecks, das Sie in Java oder anderen Garbage Collection-Sprachen haben können.

    – Ebene

    25. Juni 2015 um 18:50 Uhr

  • Siehe auch diese Antwort in der Valgrind-FAQ zu “noch erreichbaren” Blöcken, die von STL erstellt werden. valgrind.org/docs/manual/faq.html#faq.reports

    – John Perry

    14. Juni 2016 um 21:16 Uhr

  • “Das argumentieren viele Programmierer (zu Recht). [leaked memory] nicht wirklich posieren [a] Problem und sollten daher nicht als echte Speicherlecks betrachtet werden” – Lol … Erstellen Sie eine native DLL mit dieser Art von Speicherleck und lassen Sie sie dann von Java oder .Net verbrauchen. Java und .Net laden und entladen DLLs tausende Male während der Lebensdauer eines Programms. Jedes Mal, wenn die DLL neu geladen wird, verliert sie etwas mehr Speicher. Langlaufenden Programmen wird schließlich der Arbeitsspeicher ausgehen. Es treibt Debians OpenJDK-Betreuer in den Wahnsinn. Er sagte dasselbe auf der OpenSSL-Mailingliste, während wir über die „gutartigen“ Speicherlecks von OpenSSL diskutierten.

    – jww

    23. August 2018 um 16:20 Uhr


Benutzeravatar von Jens Gustedt
Jens Gustedt

Da sich unten eine Routine aus der pthread-Familie befindet (aber ich kenne diese nicht), würde ich vermuten, dass Sie einen Thread als verknüpfbar gestartet haben, der die Ausführung beendet hat.

Die Exit-Statusinformationen dieses Threads werden bis zu Ihrem Aufruf verfügbar gehalten pthread_join. Somit wird der Speicher bei Programmende in einem Verlustprotokoll gehalten, ist aber immer noch erreichbar, da Sie ihn verwenden könnten pthread_join um darauf zuzugreifen.

Wenn diese Analyse richtig ist, starten Sie diese Threads entweder losgelöst oder treten Sie ihnen bei, bevor Sie Ihr Programm beenden.

Bearbeiten: Ich habe Ihr Beispielprogramm ausgeführt (nach einigen offensichtlichen Korrekturen) und ich habe keine Fehler, aber die folgenden

==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

Seit der dl- Die Sache ähnelt weitgehend dem, was Sie sehen. Ich schätze, Sie sehen ein bekanntes Problem, für das es eine Lösung in Form einer Unterdrückungsdatei gibt valgrind. Vielleicht ist Ihr System nicht auf dem neuesten Stand oder Ihre Distribution unterstützt diese Dinge nicht. (Meins ist Ubuntu 10.4, 64bit)

  • Ich erhalte 0 Fehler, genau wie Sie. Bitte überprüfen Sie die Leak-Zusammenfassung auf Informationen zu den “Leaks”.

    Benutzer191776

    5. Oktober 2010 um 6:16 Uhr

  • @Krypto: Ich verstehe nicht. Sie meinen, Sie haben die gleichen Verdrängungen wie ich?

    – Jens Gustedt

    5. Oktober 2010 um 7:11 Uhr

  • used_suppression: 14 dl-hack3-cond-1 <- das bekomme ich

    Benutzer191776

    5. Oktober 2010 um 8:14 Uhr

Hier ist eine angemessene Erklärung für “noch erreichbar”:

„Noch erreichbar“ sind Lecks, die globalen und statisch-lokalen Variablen zugeordnet sind. Da valgrind globale und statische Variablen verfolgt, kann es Speicherzuweisungen ausschließen, die “einmal und vergessen” zugewiesen werden. Eine globale Variable, der einmal eine Zuweisung zugewiesen und diese Zuweisung nie neu zugewiesen wurde, ist typischerweise kein “Leck” in dem Sinne, dass sie nicht unbegrenzt wächst. Es ist immer noch ein Leak im engeren Sinne, kann aber normalerweise ignoriert werden, es sei denn, Sie sind pedantisch.

Lokale Variablen, denen Zuweisungen zugewiesen und nicht freigegeben werden, sind fast immer Lecks.

Hier ist ein Beispiel

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 wird working_buf als „noch erreichbar – 16k“ und temp_buf als „definitiv verloren – 5k“ melden.

Du scheinst nicht zu verstehen was still reachable meint.

Irgendetwas still reachable ist nicht ein Leck. Sie müssen nichts dagegen tun.

Für zukünftige Leser könnte “Noch erreichbar” bedeuten, dass Sie vergessen haben, so etwas wie eine Datei zu schließen. Obwohl es in der ursprünglichen Frage nicht so aussieht, sollten Sie immer sicherstellen, dass Sie dies getan haben.

  • Valgrind meldet nur durchgesickerte Dateideskriptoren mit --track-fds=yes. Sie werden nicht als „noch erreichbar“ gemeldet.

    – ZachB

    15. Dezember 2020 um 0:30 Uhr

  • Nun, wenn es mit geöffnet wurde fopendann wird das Leck für die sein FILE Struktur.

    – Syockit

    5. Januar 2021 um 2:28 Uhr

  • Valgrind meldet nur durchgesickerte Dateideskriptoren mit --track-fds=yes. Sie werden nicht als „noch erreichbar“ gemeldet.

    – ZachB

    15. Dezember 2020 um 0:30 Uhr

  • Nun, wenn es mit geöffnet wurde fopendann wird das Leck für die sein FILE Struktur.

    – Syockit

    5. Januar 2021 um 2:28 Uhr

1425190cookie-checkNoch erreichbares Leck von Valgrind entdeckt

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy