2010-09-24 24 views
9

Es stimmt, dass generische Auflistungen bessere Ergebnisse liefern als nicht generische Auflistungen für Werttypen. (d. h. Liste vs. ArrayList).Wo sind Werttypen gespeichert (C#) Generische Auflistungen

Aber warum ist das anders als der Boxen-Unboxing-Schritt? Wo werden die Objekte vom Werttyp gespeichert, sobald sie der Sammlung hinzugefügt wurden? In nicht-generischen Sammlungen werden sie in Kästchen gespeichert und auf Heap gespeichert. Was ist bei Generika anders?

+0

Für die gleiche Anzahl von ganzen Zahlen, sizeof (Liste ) ~ = sizeof (int []) ~ = 1/2 sizeof (ArrayList auf x86) ~ = 1/3 sizeof (ArrayList auf x86-64). Außerdem saugt Lokalität von Daten auf ArrayList aufgrund von Boxen und es erzeugt höher als notwendig Speicherfragmentierung. –

Antwort

1

Eine ArrayList ist ein lokales Array von Verweisen auf Objekte, die im Heap gespeichert sind.

Eine generische Liste von Verweistypen ist ein lokales Array von Verweisen auf Objekte, die im Heap gespeichert sind.

Eine generische Liste von Werttypen ist ein lokales Array dieser Werttypen.

Es gibt zwei Bereiche des Speichers, die meisten Referenzen nennen "The Stack" und "The Heap". Die meisten Leute, die diese Begriffe benutzen, haben keine Ahnung warum. ("The Stack" kann ein Stapel sein, aber The Heap ist fast sicher kein Heap). Ich bevorzuge die Begriffe "Over Here" und "Over There". Wenn boxed, werden die Daten des Werttyps "Over There" gespeichert. Wenn sie in einem Array gespeichert sind (vielleicht in einer generischen Liste), werden die Daten des Werttyps "Über hier" gespeichert. "Hier drüben" ist besser.

+0

"Hier drüben" - "da drüben" ??? Was???? Und was ist ein "lokales Array"? Diese Antwort ist verwirrender als alles andere. –

+0

@ 0xA3: Ein lokales Array ist eines, das in "The Stack" gespeichert ist. Ist es aufklärender formuliert so? –

+2

OK, dann ist deine Aussage nicht korrekt (wenn du Stapel im üblichen Sinn meinst).Sowohl "ArrayList" als auch "List " verwenden ein System.Array als internen Speicher, der ein Referenztyp ist und "dort" gespeichert wird. –

11

In Generics, wie List<T>, sind sie immer noch auf dem Heap gespeichert. Der Unterschied besteht darin, dass intern ein List<int> ein einzelnes Array von ganzen Zahlen erstellt und die Zahlen direkt speichern kann. Mit ArrayList speichern Sie am Ende ein Array mit Referenzen auf Boxed Integer-Werte.

0

Es gibt mehrere Gründe neben Boxen und Unboxing, einschließlich Speicher-Caching und die Art und Weise, wie sie aufgezählt werden, um ihre Aufgaben auszuführen. Überprüfen Sie this post, especially the comments.

0

Die Leistungsgewinne bei Generika beziehen sich im Allgemeinen nur auf Werttypen, die mit Generika verwendet werden, verglichen mit Werttypen, die in nicht-generischen Entsprechungen gespeichert sind.

Dies liegt daran, dass Werttypen mit Generics nicht zum Objekt umgewandelt und auf dem Heap gespeichert werden müssen (Boxed). Tatsächlich können sie auf dem Stapel bleiben, der leistungsfähiger ist.

http://msdn.microsoft.com/en-us/library/ms172181.aspx

8

Das entsprechende Umsetzung Detail ist, dass die darunter liegenden Speicher für ein List<T> a T []. Für eine List<int> werden die Werte in einem int [] gespeichert. Die Ganzzahlen werden in einem zusammenhängenden Teil des Speichers gespeichert, der von dem auf Müll gesammelten Haufen zugeteilt wird.

Was es so schnell macht, ist nicht nur, dass die ganzen Zahlen nicht eingerahmt sind, sondern dass ein int [] so gut mit dem CPU-Cache zusammenarbeitet. Wenn Sie das erste Element lesen, erhalten Sie im Wesentlichen die nächsten 15 kostenlos, ohne den langsamen RAM oder sekundären Cache lesen zu müssen. Dies funktioniert nicht annähernd so gut für einen Box Int, weil es so groß ist und die zusätzliche Referenz eine schlechte Cache-Lokalität haben kann. Allerdings hilft der Garbage Collector wirklich, die Kosten durch Komprimieren des Heaps zu senken.

+0

Ah, die einzige Antwort, die explizit sagt, dass 'List ' in der Tat ein Array als Backing-Speicher verwendet (und auch gut). Eine 'Liste ' ist einfach ein Wrapper für ein Array, das Unterstützung für die Größenanpassung hinzufügt, und tatsächlich stammen fast alle Collection-Typen aus Arrays, außer für spezielle Collections wie 'LinkedList '. –

+0

So hat eine 'ArrayList' einen doppelten Performance-Hit. Zuerst müssen Sie den Wert aus dem Array dereferenzieren, um das Objekt zu erhalten (Boxed-Wert-Typ), und dann müssen Sie es auspacken. –

+0

Wenn jedoch der Sicherungsspeicher für 'ArrayList'' object [] 'ist, müssen Sie zuerst das Element im Array nachschlagen, das Ihnen einen Verweis auf das Objekt gibt, das den int enthält. Sie müssen deneferenzieren, um das Objekt zu erhalten, dann müssen Sie es auspacken. Vergleichen Sie das mit 'List', wo Sie nur das Element aus dem' int [] 'Backing Store holen müssen. –