Wie geht der verwaltete .net-Speicher mit Werttypen innerhalb von Objekten um?

StackOverflow https://stackoverflow.com/questions/24829

  •  09-06-2019
  •  | 
  •  

Frage

public class MyClass
{
    public int Age;
    public int ID;
}

public void MyMethod() 
{
    MyClass m = new MyClass();
    int newID;
}

Nach meinem Verständnis trifft Folgendes zu:

  1. Die Referenz m befindet sich auf dem Stapel und verlässt den Gültigkeitsbereich, wenn MyMethod() beendet wird.
  2. Der Werttyp newID befindet sich auf dem Stapel und verlässt den Gültigkeitsbereich, wenn MyMethod() beendet wird.
  3. Das vom neuen Operator erstellte Objekt befindet sich im Heap und kann vom GC zurückgewonnen werden, wenn MyMethod() beendet wird, vorausgesetzt, dass kein anderer Verweis auf das Objekt vorhanden ist.

Hier ist meine Frage:

  1. Leben Werttypen innerhalb von Objekten auf dem Stapel oder dem Heap?
  2. Ist das Boxen/Unboxing von Werttypen in einem Objekt ein Problem?
  3. Gibt es detaillierte, aber dennoch verständliche Ressourcen zu diesem Thema?

Logischerweise würde ich annehmen, dass Werttypen innerhalb von Klassen im Heap liegen würden, aber ich bin mir nicht sicher, ob sie eingepackt werden müssen, um dorthin zu gelangen.

Bearbeiten:

Empfohlene Lektüre zu diesem Thema:

  1. CLR über C# von Jeffrey Richter
  2. Essential .NET von Don Box
War es hilfreich?

Lösung

Werttypwerte für eine Klasse haben zusammen mit der Objektinstanz im verwalteten Heap leben.Der Stapel des Threads für eine Methode bleibt nur für die Dauer einer Methode bestehen.Wie kann der Wert bestehen bleiben, wenn er nur innerhalb dieses Stapels vorhanden ist?

Die Objektgröße einer Klasse im verwalteten Heap ist die Summe ihrer Werttypfelder, Referenztypzeiger und zusätzlicher CLR-Overhead-Variablen wie dem Sync-Blockindex.Wenn man dem Werttypfeld eines Objekts einen Wert zuweist, kopiert die CLR den Wert in den Bereich, der innerhalb des Objekts für dieses bestimmte Feld zugewiesen ist.

Nehmen Sie zum Beispiel eine einfache Klasse mit einem einzelnen Feld.

public class EmbeddedValues
{
  public int NumberField;
}

Und damit ein einfacher Testkurs.

public class EmbeddedTest
{
  public void TestEmbeddedValues()
  {
    EmbeddedValues valueContainer = new EmbeddedValues();

    valueContainer.NumberField = 20;
    int publicField = valueContainer.NumberField;
  }
}

Wenn Sie den vom .NET Framework SDK bereitgestellten MSIL-Disassembler verwenden, um einen Blick auf den IL-Code für EmbeddedTest.TestEmbeddedValues() zu werfen.

.method public hidebysig instance void  TestEmbeddedValues() cil managed
{
  // Code size       23 (0x17)
  .maxstack  2
  .locals init ([0] class soapextensions.EmbeddedValues valueContainer,
           [1] int32 publicField)
  IL_0000:  nop
  IL_0001:  newobj     instance void soapextensions.EmbeddedValues::.ctor()
  IL_0006:  stloc.0
  IL_0007:  ldloc.0
  IL_0008:  ldc.i4.s   20
  IL_000a:  stfld      int32 soapextensions.EmbeddedValues::NumberField
  IL_000f:  ldloc.0
  IL_0010:  ldfld      int32 soapextensions.EmbeddedValues::NumberField
  IL_0015:  stloc.1
  IL_0016:  ret
} // end of method EmbeddedTest::TestEmbeddedValues

Beachten Sie, dass die CLR dazu aufgefordert wird stfld Der geladene Wert „20“ im Stapel wird an die geladene Position des NumberField-Felds von EmbeddValues ​​direkt in den verwalteten Heap verschoben.Ebenso wird beim Abrufen des Werts verwendet ldfld Anweisung, den Wert direkt aus diesem verwalteten Heap-Speicherort in den Thread-Stapel zu kopieren.Bei dieser Art von Vorgängen findet kein Ein-/Auspacken statt.

Andere Tipps

  1. Alle Referenzen oder Werttypen, die ein Objekt im Haufen leben.
  2. Nur wenn Sie INTs in Objekte werfen.

Die beste Ressource, die ich dafür gesehen habe, ist das Buch CLR über C# von Jeffrey Richter. Es lohnt sich zu lesen, wenn Sie eine .NET -Entwicklung durchführen. Basierend auf diesem Text ist mein Verständnis, dass die Werttypen innerhalb eines Referenztyps im Haufen leben, das in das übergeordnete Objekt eingebettet ist. Referenztypen sind stets auf dem Haufen. Boxen und Unboxen sind nicht symmetrisch. Boxen können ein größeres Problem sein als das Entbinden. Boxen Wille Erfordern Sie das Kopieren des Inhalts des Werttyps vom Stapel auf den Haufen. Je nachdem, wie häufig dies Ihnen passiert, kann es keinen Sinn haben, eine Struktur anstelle einer Klasse zu haben. Wenn Sie einen leistungskritischen Code haben und nicht sicher sind, ob Boxen und Unboxing stattfinden, verwenden Sie ein Tool, um den IL -Code Ihrer Methode zu untersuchen. Sie werden die Wörter Box und Unbox in der IL sehen. Persönlich würde ich die Leistung meines Codes messen und nur dann prüfen, ob dies ein Kandidat für Sorgen ist. In Ihrem Fall denke ich nicht, dass dies ein so kritisches Problem sein wird. Sie müssen nicht jedes Mal, wenn Sie diesen Werttyp im Referenztyp auf diesen Werttyp zugreifen, aus dem Stapel zum Heap (Box) kopieren. In diesem Szenario wird das Boxen zu einem bedeutungsvolleren Problem.

  • Ans#1: Haufen. Umschreiben von Don Box aus seinem hervorragenden "Essential .net Vol 1"

Referenztypen (RT) ergeben immer Instanzen, die auf dem Haufen zugewiesen werden. Im Gegensatz dazu sind Werttypen (VT) vom Kontext abhängig - wenn ein lokaler VaR ein VT ist, weist der CLR Speicher auf dem Stapel zu. Wenn ein Feld in einer Klasse ein Mitglied eines VT ist, weist der CLR Speicher für die Instanz als Teil des Layouts des Objekts/Typs zu, in dem das Feld deklariert wird.

  • ANS#2: Nein. Das Boxen würde nur dann auftreten, wenn Sie über einen Objektreferenz- / Schnittstellenzeiger auf eine Struktur zugreifen. Obinstance.vt_typedfield wird nicht boxen.

    RT -Variablen enthält die Adresse des Objekts, auf das es sich bezieht. 2 RT Var kann auf dasselbe Objekt verweisen. Im Gegensatz dazu sind VT -Variablen die Instanzen selbst. 2 VT var kann nicht auf das gleiche Objekt hinweisen (Struktur)

  • ANS#3: DON BOXs Essential .net / Jeffrey Richters CLR über C#. Ich habe eine Kopie des ersteren ... obwohl der spätere möglicherweise für .NET -Revisionen besser aktualisiert werden kann

Leben Werttypen in Objekten auf dem Stapel oder auf dem Haufen?

Auf dem Haufen. Sie sind Teil der Zuweisung des Fußabdrucks des Objekts, genau wie die Zeiger, die Referenzen halten würden.

Ist das Box-/Unboxing -Werttypen in einem Objekt ein Problem?

Hier gibt es kein Boxen.

Gibt es detaillierte und dennoch verständliche Ressourcen zu diesem Thema?

+1 Stimmen Sie für Richters Buch.

Eine Variable oder ein anderer Speicherort eines Strukturtyps ist eine Aggregation der öffentlichen und privaten Instanzfelder dieses Typs. Gegeben

struct Foo {public int x,y; int z;}

eine Erklärung Foo bar; wird verursachen bar.x, bar.y, und bar.z Überall aufbewahrt werden bar wird gespeichert. Hinzufügen einer solchen Erklärung von bar zu einer Klasse wird aus Sicht der Speicher-Layout-Sicht gleich mit dem Hinzufügen von drei entsprechen int Felder. In der Tat, wenn man nie etwas mitgeteilt hat bar außer Zugang zu seinen Feldern, die Felder von bar würde sich genauso verhalten wie drei Felder bar_x, bar_y, und bar_cantaccessthis_z Zugriff auf die letzte müsste Dinge mit tun, mit bar Abgesehen von dem Zugriff auf seine Felder, aber es würde Platz in Anspruch nehmen, ob es jemals für irgendetwas verwendet wird oder nicht.

Das Erkennen von Strukturspeicherorten als Aggregationen von Feldern ist der erste Schritt zum Verständnis von Strukturen. Der Versuch, sie als eine Art Objekt zu halten, mag "einfacher" erscheinen, entspricht aber nicht, wie sie tatsächlich funktionieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top