Cyclic Garbage Collection

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Maple99
User
Beiträge: 44
Registriert: Montag 14. September 2009, 18:08

Moin,

ich habe mal eine frage zur Auflösung der zyklischen Abhängigkeiten und damit verbundenen Speicherfreigabe. Leider wird nämlich bei mir der Speicher nicht freigegeben (jedenfalls glaube ich das es so ist). Folgende Funktionen habe ich implementiert:

Code: Alles auswählen

static int
My_traverse(MyObject *self, visitproc visit, void *arg) {
    unsigned int i;
    int res = 0;
    for (i = 0; (i < self->len) && (res == 0); ++i) {
        res = visit(self->e[i], arg);
        PySys_WriteStdout("Res = %d\n", res);
    }
    return res;
}

static int
My_clear(MyObject* self) {
    unsigned int i;

    PySys_WriteStdout("Clear");

    for (i = 0; i < self->len; ++i) {
        Py_CLEAR(self->e[i]);
    }
    return 0;
}
static void
My_dealloc(MyObject *self) {
    My_clear(self);
    Py_TYPE(self)->tp_free((PyObject*) self);
    PySys_WriteStdout("%s", "fertig\n");
}

Wenn ich eine zyklische Verkettung einbaue und danach "del myVar" aufrufe, dann erscheint der Text "fertig" nicht, so dass ich annehme das das dealloc nicht ausgeführt wird. Wenn ich den Interpreter verlasse erscheint die "Res-Ausgabe" 2*self->len Mal, aber der Wert ist immer 0. Eigentlich sollte er doch mal <> 0 sein, wenn die visit-function einen Zyklus entdeckt hat. Leider scheint sie den nicht zu finden, denn ich sehe keine "Clear" und keine "Fertig"-Ausgabe ;(
Hat jemand vielleicht einen Tip für mich woran es liegen kann?

Gruß

Jonny

P.s. Im TypeObject sind dealloc, traverse und clear registriert und Py_TPFLAGS_HAVE_GC ist gesetzt.
BlackJack

@Maple99: Wie und wo führst Du den ``del myVar`` aus? Bist Du sicher, dass es danach wirklich keine Referenz mehr auf das Objekt gibt?
Maple99
User
Beiträge: 44
Registriert: Montag 14. September 2009, 18:08

Hi,

also ich führe folgenden Code im Interpreter aus:

Code: Alles auswählen

from MyModule import *
# 5 ist die Anzahl der Elemente in e
a = MyType(5)
a = a.add(a)
del a
Jetzt sollte ja eigentlich der Speicher aufgeräumt werden, aber es passiert wie gesagt leider nichts. Wenn ich statt a eine Zahl oder ein anderes Objekt "adde" dann wird alles korrekt aufgeräumt.

Gruß

Jonny
Maple99
User
Beiträge: 44
Registriert: Montag 14. September 2009, 18:08

Hi,

hat vielleicht irgendjemand noch mal einen Tip wo ich noch mal schauen kann??
derdon
User
Beiträge: 1316
Registriert: Freitag 24. Oktober 2008, 14:32

Maple99 hat geschrieben:Jetzt sollte ja eigentlich der Speicher aufgeräumt werden, aber es passiert wie gesagt leider nichts.
del räumt nicht den Speicher auf, es wird lediglich der Name, der auf das Objekt verweist, entfernt (aber nicht das Objekt selbst!).
http://docs.python.org/reference/simple_stmts.html#the-del-statement hat geschrieben:Deletion of a name removes the binding of that name from the local or global namespace, depending on whether the name occurs in a global statement in the same code block.
Maple99
User
Beiträge: 44
Registriert: Montag 14. September 2009, 18:08

Hi,

okay danke für die Antwort, aber wie bewege ich den Interpreter denn dazu den Speicher dann bitte auch gleich mal freizugeben??

Gruß

Jonny
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

evtl über ``gc.collect()``
Maple99
User
Beiträge: 44
Registriert: Montag 14. September 2009, 18:08

Hi,

danke, das habe ich auch schon mal getestet. Leider ist das so eine Erscheinung das der Garbage Collector den Speicher nur manchmal aufräumt ;(
Kann mir jemand erklären was die visit-Function genau tut bzw. was der Parameter args soll??
Meiner Meinung ist die Python-Doku sehr zurückhaltend mit Details ;(
BlackJack

@Maple99: Ich denke mal das braucht man an der Stelle einfach nicht zu wissen. Und wenn man es doch wissen möchte -- der Quelltext ist ja verfügbar.

Wenn ich mal raten müsste, dann sorgt die Funktion dafür, dass bei den übergebenen Objekten ebenfalls die `traverse`-Funktion aufgerufen wird, und das `args` auf eine Struktur verweist, in der aufgezeichnet wird, welche Objekte schon besucht wurden. Eben um Kreise in dem Objektgraphen zu finden.

Bist Du ganz sicher, dass es keine Referenz mehr auf das Objekt gibt? Beliebte "Fallen" sind zum Beispiel der Name `_` im interaktiven Python-Shell oder bei `ipython` *alles* was mal als Ergebnis in einer Sitzung kam, oder die letzte Ausnahme, die vielleicht noch über irgendeinen Stackframe eine Referenz hält.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

gibt am besten mal ein *komplettes* Minimalbeispiel mit allen notwendigen Sourcen an.
Antworten