Referenz-Zählung

Objekte oder Datenblöcke werden immer an einer nachvollziehbaren Stelle erzeugt. Aber beim Freigeben ist es nicht immer so leicht vorzugeben, wo das geschehen soll.

Das Problem trifft oft Bibliotheken, deren Nutzer andere Entwickler sind.

Die schlimmste (aber auch speicher-schonenste) Variante, ist die alte C-Lösung, dass Ergebnisse in einer globalen Variable landen und die Daten-nutzende Komponente einen Pointer dort hin erhält.

strtok() ist so ein Negativbeispiel. Hätten die Compiler-Hersteller nicht auf Thread-lokalen Speicher anstatt von globalem umgestellt, wäre Multithreading bis heute nicht möglich. … und dann passiert es, wenn ein Thread unerwartet terminiert, dass ein Memory-Leak sichtbar wird.

Besser ist es, immer eine Deallocation-Funktion bereitzustellen.

1foo* f = create_foo();
2do_something_with(f);
3delete_foo(f);

Hier muss der Nutzer wissen, wann die Ressource nicht mehr gebraucht wird und kann sie manuell freigeben. Oft passiert es aber, dass eine Ressource von zwei Komponenten gemeinsam genutzt wird. Nun sollte die langlebigere die Freigabe übernehmen und die andere nur den Pointer aufbewahren.

Reference-Counting ist, denke ich, die beste und portabelste Möglichkeit, Speicher sicher und unaufwendig zu verwalten. Wenn jedes Objekt neben seinen Daten noch einen Referenz-Zähler beinhaltet, der bei Beginn der Nutzung hochgezählt wird und danach wieder heruntergezählt wird, kann beim Herunterzählen Code ausgeführt werden, der bei der Erreichung von Null automatisch die Löschung durchführt.

Microsoft’s COM basiert auf dieser Idee. Jedes (und zwar wirklich jedes) Objektinterface startet mit den Methoden AddRef() und Release().

Wird ein Objekt erzeugt steht sein Counter auf 1 und gehört dem initialen Besitzer. Immer wenn ein neuer Pointer auf das Objekt gesetzt wird, ruft man AddRef() auf, wenn ein Pointer nicht mehr benutzt wird, ruft man Release() auf.

C++ Freunde nutzen dafür ein Smart-Pointer Template und so kann man mit üblichen C++ Copy-Konstrukturen und Destruktoren den Rest implementieren. Der Overhead von Reference-Counting besteht aus einer Addition, einer Subtraktion und einem Gegen-Null-Vergleich. Das ist verkraftbar.

Smart-Pointer Implementierung nutzen in der Regel ebenfalls Reference- Counting um die Lebenszeit von Objekten zu bestimmen. Während bei COM das sogenannte Intrusive-Reference-Counting genutzt wird, wo der Counter ein Teil des Objektes ist, nutzen SmartPointer “Non-Intrusive-Reference-Counting”, wo der Counter in einem Objekt gehalten wird und auf das eigentlich Objekt weiterverwiesen wird. So kann std::smart_ptr auch Objekte verwalten, die von Reference-Counting nichts wissen.

Das GATE Projekt nutzt an vielen Stellen Reference-Counting. Vor allem dort, wo Daten aus einer Komponente herausgenommen werden und ohne die Komponente weiter verwertet werden sollen.

Natürlich soll man es nicht übertreiben, denn dort wo von Anfang an feststeht, dass ein Objekt nur einmal benutzt werden kann, kann man auf die Referenz-Buchführung natürlich verzichten.


Wenn sich eine triviale Erkenntnis mit Dummheit in der Interpretation paart, dann gibt es in der Regel Kollateralschäden in der Anwendung.
frei zitiert nach A. Van der Bellen
... also dann paaren wir mal eine komplexe Erkenntnis mit Klugheit in der Interpretation!