Freigeben über


Regeln für die Verwaltung von Referenzanzahlen

Die Verwendung einer Referenzanzahl zum Verwalten der Objektlebensdauer ermöglicht es mehreren Clients, den Zugriff auf ein einzelnes Objekt abzurufen und freizugeben, ohne sich bei der Verwaltung der Objektlebensdauer aufeinander abstimmen zu müssen. Solange das Clientobjekt bestimmten Verwendungsregeln entspricht, stellt das Objekt diese Verwaltung bereit. Diese Regeln geben an, wie Referenzen zwischen Objekten verwaltet werden. (COM gibt keine internen Implementierungen von Objekten an, obwohl diese Regeln ein vernünftiger Ausgangspunkt für eine Richtlinie innerhalb eines Objekts sind.)

Konzeptuell können Schnittstellenzeiger als innerhalb von Zeigervariablen betrachtet werden, die den gesamten internen Status des Berechnungsergebnis enthalten, der einen Schnittstellenzeiger enthält. Dazu gehören Variablen an Speicherorten, in internen Prozessorregistern und sowohl von Programmierern generierte als auch vom Compiler generierte Variablen. Die Zuweisung oder Initialisierung einer Zeigervariable umfasst das Erstellen einer neuen Kopie eines bereits vorhandenen Zeigers. Wo eine Kopie des Zeigers in einer Variablen vorhanden war (der Wert, der in der Zuordnung/Initialisierung verwendet wird), gibt es jetzt zwei. Eine Zuordnung zu einer Zeigervariable zerstört die Zeigerkopie in der Variablen, ebenso wie die Zerstörung der Variablen selbst. (Das heißt, der Bereich, in dem die Variable gefunden wird, z. B. der Stapelrahmen, wird zerstört.)

Aus Sicht eines COM-Clients erfolgt die Referenzzählung immer für jede Schnittstelle. Clients sollten niemals davon ausgehen, dass ein Objekt denselben Zähler für alle Schnittstellen verwendet.

Der Standardfall ist, dass AddRef für jede neue Kopie eines Schnittstellenzeigers aufgerufen werden muss und Release für jede Zerstörung eines Schnittstellenzeigers aufgerufen werden muss, es sei denn, die folgenden Regeln erlauben andernfalls:

  • In-out Parameter für Funktionen Die aufrufende Funktion muss AddRef für den Parameter aufrufen, da es (mit einem Aufruf von Release) im Implementierungscode freigegeben wird, wenn der Ausgabewert darüber gespeichert wird.
  • Fetchen einer globalen Variablen. Beim Erstellen einer lokalen Kopie eines Schnittstellenzeigers aus einer vorhandenen Kopie des Zeigers in einer globalen Variable müssen Sie AddRef für die lokale Kopie aufrufen, da eine andere Funktion die Kopie in der globalen Variablen zerstören kann, während die lokale Kopie noch gültig ist.
  • Neue Zeiger synthetisiert aus „dünner Luft“. Eine Funktion, die einen Schnittstellenzeiger mithilfe spezieller interner Kenntnisse synthetisiert, anstatt sie von einer anderen Quelle zu erhalten, muss AddRef zunächst für den neu synthetisierten Zeiger aufrufen. Wichtige Beispiele für solche Routinen sind Instanzenerstellungsroutinen, Implementierungen von QueryInterface usw.
  • Abrufen einer Kopie eines intern gespeicherten Zeigers. Wenn eine Funktion eine Kopie eines Zeigers abruft, der intern vom aufgerufenen Objekt gespeichert wird, muss der Code dieses Objekts AddRef auf dem Zeiger aufrufen, bevor die Funktion zurückgegeben wird. Nachdem der Zeiger abgerufen wurde, hat das ursprüngliche Objekt keine andere Möglichkeit, zu bestimmen, wie sich die Lebensdauer auf die intern gespeicherte Kopie des Zeigers bezieht.

Die einzigen Ausnahmen vom Standardfall erfordern, dass der Verwaltungscode die Beziehungen der Lebensdauer von zwei oder mehr Kopien eines Zeigers auf die gleiche Schnittstelle für ein Objekt kennt und einfach sicherstellen, dass das Objekt nicht zerstört wird, indem die Referenzanzahl auf Null gesetzt wird. Es gibt in der Regel zwei Fälle, wie folgt:

  • Wenn eine Kopie eines Zeigers bereits vorhanden ist und eine zweite anschließend erstellt und dann zerstört wird, während die erste Kopie noch vorhanden ist, können Aufrufe von AddRef und Release für die zweite Kopie weggelassen werden.
  • Wenn One Copy eines Zeigers existiert und eine zweite erstellt wird und die erste vor der zweiten zerstört wird, können die Aufrufe von AddRef für die zweite Kopie und zum Release für die erste Kopie weggelassen werden.

Im Folgenden finden Sie spezifische Beispiele für diese Situationen, wobei die ersten beiden besonders häufig vorkommen:

  • In Parametern für Funktionen Die Lebensdauer der Kopie eines Schnittstellenzeigers, der als Parameter an eine Funktion übergeben wird, wird in der des Zeigers geschachtelt, der zum Initialisieren des Werts verwendet wird, sodass für den Parameter keine separate Referenzanzahl erforderlich ist.
  • Ausgabeparameter aus Funktionen, einschließlich Rückgabewerten. Zum Festlegen des Ausgabeparameters muss die Funktion über eine stabile Kopie des Schnittstellenzeigers verfügen. Beim Zurücksenden ist der Aufrufer ist für das Freigeben des Zeigers verantwortlich. Daher benötigt der Ausgabeparameter keine separate Referenzanzahl.
  • Lokale Variablen. Eine Methodenimplementierung hat die Kontrolle über die Lebensdauer der einzelnen Zeigervariablen, die auf dem Stapelframe zugeordnet sind, und kann dies verwenden, um zu bestimmen, wie redundante AddRef/Release-Paare weggelassen werden.
  • Backpointer. Einige Datenstrukturen enthalten zwei Objekte, jeweils mit einem Zeiger auf die andere. Wenn die Lebensdauer des ersten Objekts bekannt ist, die Lebensdauer des zweiten Objekts zu enthalten, ist es nicht erforderlich, eine Verweisanzahl auf den Zeiger des zweiten Objekts auf das erste Objekt zu haben. Oft ist es wichtig, diesen Zyklus zu vermeiden, um ein angemessenes Belegungsfreigabe-Verhalten aufrechtzuerhalten. Allerdings sollten nicht gezählte Zeiger mit äußerster Vorsicht verwendet werden, da der Teil des Betriebssystems, das die Remoteverarbeitung verarbeitet, keine Möglichkeit hat, diese Beziehung zu kennen. Daher ist es in fast allen Fällen die bevorzugte Lösung, den Backpointer ein zweites, „befreundetes“ Objekt des ersten Zeigers sehen zu lassen (und so den Zirkelschluss zu vermeiden). Die Architektur von verbindungsfähigen Objekten von COM verwendet z. B. diesen Ansatz.

Bei der Implementierung oder Verwendung von referenzgezählten Objekten kann es nützlich sein, künstliche Referenzanzahlen anzuwenden, die die Objektstabilität während der Verarbeitung einer Funktion garantieren. Bei der Implementierung einer Methode einer Schnittstelle rufen Sie möglicherweise Funktionen auf, die die Referenzanzahl auf ein Objekt erhöhen können, was zu einer vorzeitigen Veröffentlichung des Objekts und eines Fehlers der Implementierung führt. Eine robuste Möglichkeit, dies zu vermeiden, besteht darin, einen Aufruf von AddRef am Anfang der Methodenimplementierung einzufügen und sie mit einem Aufruf von Release direkt vor dem Zurückgeben der Methode zu koppeln.

In einigen Fällen sind die Rückgabewerte von AddRef und Release möglicherweise instabil und sollten nicht verwendet werden. Sie sollten nur für Debugging- oder Diagnosezwecke verwendet werden.

Verwalten von Objektlebensdauern durch Referenzzählung