Ich bin verwirrt mit den Grundlagen der Speicherzuweisung zwischen Stack und Heap . Gemäß der Standarddefinition (Dinge, die jeder sagt) werden alle Werttypen einem Stapel zugewiesen und Referenztypen werden in den Heap verschoben .
Betrachten Sie nun das folgende Beispiel:
class MyClass
{
int myInt = 0;
string myString = "Something";
}
class Program
{
static void Main(string[] args)
{
MyClass m = new MyClass();
}
}
Wie erfolgt nun die Speicherzuweisung in c #? Wird das Objekt von MyClass
(das heißt m
) vollständig dem Heap zugeordnet? Das heißt, int myInt
und string myString
beide werden auf Haufen gehen?
Oder wird das Objekt in zwei Teile geteilt und den beiden Speicherorten Stack und Heap zugewiesen?
Antworten:
m
wird auf dem Heap zugewiesen, und das schließt einmyInt
. Die Situationen, in denen primitive Typen (und Strukturen) auf dem Stapel zugewiesen werden, treten während des Methodenaufrufs auf, wodurch Platz für lokale Variablen auf dem Stapel zugewiesen wird (weil dies schneller ist). Zum Beispiel:class MyClass { int myInt = 0; string myString = "Something"; void Foo(int x, int y) { int rv = x + y + myInt; myInt = 2^rv; } }
rv
,x
,y
Werden alle auf dem Stapel sein.myInt
befindet sich irgendwo auf dem Heap (und muss über denthis
Zeiger zugänglich sein ).quelle
Sie sollten die Frage, wo Objekte zugewiesen werden, als Implementierungsdetail berücksichtigen . Es spielt für Sie keine Rolle, wo genau die Bits eines Objekts gespeichert sind. Es kann wichtig sein, ob ein Objekt ein Referenztyp oder ein Werttyp ist, aber Sie müssen sich keine Gedanken darüber machen, wo es gespeichert wird, bis Sie das Verhalten der Speicherbereinigung optimieren müssen.
Während Referenztypen in aktuellen Implementierungen immer auf dem Heap zugewiesen werden, können Werttypen auf dem Stapel zugewiesen werden - müssen dies aber nicht. Ein Werttyp wird nur dann auf dem Stapel zugewiesen, wenn es sich um eine nicht maskierte lokale oder temporäre Variable ohne Box handelt, die nicht in einem Referenztyp enthalten und nicht in einem Register zugeordnet ist.
Gibt es etwas, das ich verpasst habe?
Natürlich wäre ich mir nicht sicher, wenn ich nicht auf Eric Lipperts Beiträge zum Thema verlinken würde:
quelle
"Alle VALUE-Typen werden dem Stapel zugewiesen" ist sehr, sehr falsch. Strukturvariablen können als Methodenvariablen auf dem Stapel leben. Felder in einem Typ leben jedoch mit diesem Typ . Wenn der deklarierende Typ eines Felds eine Klasse ist, befinden sich die Werte als Teil dieses Objekts auf dem Heap . Wenn der deklarierende Typ eines Feldes eine Struktur ist, sind die Felder Teil dieser Struktur, wo immer diese Struktur lebt.
Sogar Methodenvariablen können sich auf dem Heap befinden, wenn sie erfasst werden (Lambda / Anon-Methode) oder Teil (zum Beispiel) eines Iteratorblocks.
quelle
object x = 12;
eine Methode haben, wird die 12 auf dem Heap gespeichert, obwohl es sich um eine Ganzzahl (einen Werttyp) handelt.null
oder ein Verweis auf ein Heap-Objekt des entsprechenden Typs. Für jeden Werttyp gibt es einen entsprechenden Heap-Objekttyp; Wenn Sie versuchen, einen Werttyp in einem Speicherort vom Referenztyp zu speichern, wird ein neues Objekt des entsprechenden Heap-Objekttyps erstellt, alle Felder in dieses neue Objekt kopiert und ein Verweis auf das Objekt im Speicherort des Referenztyps gespeichert. C # gibt vor, dass derList<T>.Enumerator
das in einer Variablen dieses Typs gespeichert ist, weist eine Wertesemantik auf , da es sich um einen Wertetyp handelt. A,List<T>.Enumerator
das in einer Variablen vom Typ gespeichert istIEnumerator<T>
, verhält sich jedoch wie ein Referenztyp. Betrachtet man den letzteren als einen anderen Typ als den ersteren, so ist der Unterschied im Verhalten leicht zu erklären. Wenn Sie so tun, als wären sie vom selben Typ, ist es viel schwieriger, über sie nachzudenken.Hervorragende Erklärung:
Teil 1: http://www.c-sharpcorner.com/uploadfile/rmcochran/csharp_memory01122006130034pm/csharp_memory.aspx
Teil 2: http://www.c-sharpcorner.com/UploadFile/rmcochran/csharp_memory2B01142006125918PM/csharp_memory2B.aspx
Teil 3: http://www.c-sharpcorner.com/UploadFile/rmcochran/chsarp_memory401152006094206AM/chsarp_memory4.aspx
Teil 4: http://www.c-sharpcorner.com/uploadfile/rmcochran/csharp_memory_401282006141834pm/csharp_memory_4.aspx
quelle
Stapel
Betrachten Sie die folgende Methode:
public static int Factorial (int x) { if (x == 0) { return 1; } return x * Factorial (x - 1); }
Diese Methode ist rekursiv, dh sie ruft sich selbst auf. Jedes Mal, wenn die Methode eingegeben wird, wird ein neues int auf dem Stapel zugewiesen , und jedes Mal , wenn die Methode beendet wird, wird das int freigegeben .
Haufen
Betrachten Sie die folgende Methode:
using System; using System.Text; class Test { public static void Main() { StringBuilder ref1 = new StringBuilder ("object1"); Console.WriteLine (ref1); // The StringBuilder referenced by ref1 is now eligible for GC. StringBuilder ref2 = new StringBuilder ("object2"); StringBuilder ref3 = ref2; // The StringBuilder referenced by ref2 is NOT yet eligible for GC. Console.WriteLine (ref3); // object2 } }
Im obigen Beispiel erstellen wir zunächst ein StringBuilder-Objekt, auf das die Variable ref1 verweist, und schreiben dann dessen Inhalt aus. Dieses StringBuilder-Objekt ist dann sofort für die Speicherbereinigung berechtigt, da es anschließend von nichts verwendet wird. Anschließend erstellen wir einen weiteren StringBuilder, auf den durch die Variable ref2 verwiesen wird, und kopieren diesen Verweis auf ref3. Obwohl ref2 nach diesem Zeitpunkt nicht mehr verwendet wird, behält ref3 dasselbe StringBuilder-Objekt bei. So wird sichergestellt, dass es erst nach Abschluss von ref3 für die Erfassung geeignet ist.
quelle
einfache Maßnahmen
Der Werttyp kann auf THE STACK festgelegt werden. Dies ist das Implementierungsdetail, das der futuristischen Datenstruktur zugewiesen werden kann.
Daher ist es besser zu verstehen, wie Wert und Referenztyp funktionieren. Der Werttyp wird nach Wert kopiert, dh wenn Sie einen Werttyp als Parameter an eine FUNKTION übergeben, als wenn er von Natur aus kopiert wird, bedeutet dies, dass Sie eine vollständig neue Kopie haben .
Referenztypen werden als Referenz übergeben (wenn Sie nicht berücksichtigen, dass Referenz in einigen zukünftigen Versionen eine Adresse erneut speichert, kann sie in einigen anderen Datenstrukturen gespeichert werden.)
also in deinem Fall
myInt ist ein int, das in einer Klasse zusammengefasst ist, die einen Referenztyp enthält, sodass es an die Instanz der Klasse gebunden ist, die in 'THE HEAP' gespeichert wird.
Ich würde vorschlagen, Sie können anfangen, Blogs zu lesen, die von ERIC LIPPERTS geschrieben wurden.
Erics Blog
quelle
Jedes Mal, wenn ein Objekt darin erstellt wird, wird es in den als Heap bezeichneten Speicherbereich verschoben. Die primitiven Variablen wie int und double werden im Stapel zugewiesen, wenn es sich um lokale Methodenvariablen handelt, und im Heap, wenn es sich um Mitgliedsvariablen handelt. In Methoden werden lokale Variablen in den Stapel verschoben, wenn eine Methode aufgerufen wird, und der Stapelzeiger wird dekrementiert, wenn ein Methodenaufruf abgeschlossen ist. In einer Multithread-Anwendung hat jeder Thread seinen eigenen Stapel, teilt sich jedoch denselben Heap. Aus diesem Grund sollte in Ihrem Code darauf geachtet werden, dass keine gleichzeitigen Zugriffsprobleme im Heap-Bereich auftreten. Der Stapel ist threadsicher (jeder Thread hat seinen eigenen Stapel), aber der Heap ist nicht threadsicher, es sei denn, er wird durch die Synchronisierung durch Ihren Code geschützt.
Dieser Link ist auch nützlich http://www.programmerinterview.com/index.php/data-structures/difference-between-stack-and-heap/
quelle
m ist eine Referenz auf ein Objekt von MyClass, sodass m im Stapel des Hauptthreads gespeichert wird, das Objekt von MyClass jedoch im Heap. Daher speichern myInt und myString im Heap. Beachten Sie, dass m nur eine Referenz (eine Adresse zum Speicher) ist und sich auf dem Hauptstapel befindet. Wenn die Zuordnung aufgehoben wurde, löscht GC das MyClass-Objekt aus dem Heap. Weitere Informationen finden Sie in allen vier Teilen dieses Artikels unter https://www.c-sharpcorner.com/article/C-Sharp-heaping-vs-stacking-in-net- Teil-i /
quelle