2009-03-03 5 views
13

Wenn Sie sehr kleine Objekte haben müssen, sagen, dass 2 Float-Eigenschaft enthält, und Sie Millionen von ihnen haben werden, die nicht sofort "zerstört" werden, sind Strukturen eine bessere Wahl oder Klassen?Struct vs Klasse für langlebige Objekte

Wie in XNA als eine Bibliothek, gibt es Point3s usw. als Strukturen, aber wenn Sie diese Werte für eine lange Zeit halten müssen, würde es eine Leistungsbedrohung darstellen?

Antwort

33

Im Gegensatz zu den meisten Fragen über Strukturen scheint dies tatsächlich eine gute Verwendung einer Struktur zu sein. Wenn die darin enthaltenen Daten Werttypen sind und Sie viele davon verwenden werden, würde eine Struktur gut funktionieren.

Einige Tipps:

:: Die Struktur nicht größer als 16 Bytes sein sollte, oder Sie die Leistungsvorteile verlieren.

:: Machen Sie die Struktur unveränderlich. Das macht die Verwendung klarer.

Beispiel:

public struct Point3D { 

    public float X { get; private set; } 
    public float Y { get; private set; } 
    public float Z { get; private set; } 

    public Point3D(float x, float y, float z) { 
     X = x; 
     Y = y; 
     Z = z; 
    } 

    public Point3D Invert() { 
     return new Point3D(-X, -Y, -Z); 
    } 

} 
+0

Toller Beitrag, nahm heute meine letzte Erwähnung. –

+4

Dies ist wahrscheinlich eine gute Verwendung des Schlüsselworts readonly, d. H., Anstatt X, Y und Z als Eigenschaften zu deklarieren, könnten Sie schreibgeschützte Felder haben. Der Vorteil wäre, dass Sie Ihre Unveränderlichkeit nicht aus Versehen brechen würden. – Ant

+0

Ist 'myRect = new Rectangle (myRect.X, myRect.Y + 4, myRect.Width, myRect.Height);' wirklich klarer als 'myRect.Y + = 4;'? Mutierende * Methoden * für Strukturen sind problematisch, aber exponierte Felder sollten in vielen Fällen die Norm sein. – supercat

2

Die große Sorge ist, ob der Speicher auf dem Stapel oder dem Heap zugeordnet ist. Structs werden standardmäßig in den Stack aufgenommen, und der Stack ist im Allgemeinen räumlich viel begrenzter. Es kann also ein Problem sein, so viele Structs zu erstellen.

In der Praxis denke ich nicht wirklich, dass es so groß ist. Wenn Sie so viele davon haben, sind sie wahrscheinlich Teil einer Klasseninstanz (auf dem Heap).

+1

Der Stapelspeicherplatz ist kein Problem für Strukturen, da Sie selten so viele lokale Variablen haben. Wenn Sie ein Array von Strukturen erstellen, wird es auf dem Heap zugewiesen, nicht auf dem Stapel. – Guffa

+0

Ich denke, das war mein Punkt: Wenn Sie so viele haben, ist es ein Problem, aber Sie werden nicht so viele haben. –

+0

Wenn Sie so viele Variablen haben, ist es ein Problem, unabhängig davon, ob es sich um eine Struktur oder eine Klasse handelt, da die Referenzen auch auf dem Stack zugewiesen werden würden ... :) – Guffa

1

Werttypen (struct) sind gut für den Typ, der nicht häufig auf Heap zugeordnet wird, dh sie sind meist in einem anderen Referenz- oder Werttyp enthalten.

Das von Ihnen angegebene Vector3-Beispiel ist ein perfektes Beispiel. Sie werden Vector3 selten in Heap baumeln lassen, sie werden meistens in einem Typ enthalten sein, der sich selbst in Heap befindet oder als lokale Variable verwendet wird, in diesem Fall wird er auf dem Stack zugewiesen.

+0

Danke, also werden Strukturen nur dann auf dem Haufen sein, wenn sie als lokale Variable verwendet werden, und sonst nichts? –

+0

Nein, es ist anders herum. Ein Werttyp wie eine Struktur wird nur im Stapel zugeordnet, wenn es sich um eine lokale Variable handelt. Wenn es ein Mitglied einer Klasse ist, wird es als Teil des Speicherbereichs des Objekts auf dem Heap zugeordnet. – Guffa

2

Struct scheint für diese Anwendung richtig.

Bedenken Sie, dass die "Notwendigkeit, auf diese Werte zu halten" impliziert ihre Speicherung auf dem Haufen irgendwo, wahrscheinlich ein Array-Feld einer Klasseninstanz.

Eine Sache, auf die Sie achten sollten, ist, dass dies zu einer Zuweisung auf dem Heap für große Objekte führt. Es ist nicht so klar, wie, wenn überhaupt, dieser Heap defragmentiert sich selbst, aber für sehr langlebige Objekte, die vielleicht kein Problem ist.

Die Verwendung der Klasse für Millionen dieser Datentypen wäre wahrscheinlich kostenaufwendig im Hinblick auf das Dereferenzierungs-Schervolumen, das für Operationen dieser Art wahrscheinlich auftreten wird.

5

Die Antwort hängt davon ab, wo die Objekte/Werte werden schließlich gespeichert werden. Wenn sie in einer untypisierten Sammlung wie ArrayList gespeichert werden sollen, enden Sie damit, sie zu boxen. Boxing erstellt einen Objektwrapper für eine Struktur und der Footprint ist der gleiche wie bei einem Klassenobjekt. Wenn Sie andererseits ein typisiertes Array wie T [] oder List verwenden, speichert die Verwendung von Strukturen nur die tatsächlichen Daten für jedes Element, das nur für die gesamte Sammlung Footprint und nicht für seine Elemente verwendet.

So Strukturen sind effizienter für die Verwendung in T [] - Arrays.

2

In der Regel große Arrays von nicht-Aliasing (d. H.Unshared) Daten desselben Typs werden am besten in Structs für die Performance gespeichert, da Sie die Anzahl der Umleitungen reduzieren. (Siehe auch when-are-structs-the-answer). Der genaue Leistungsunterschied zwischen Klasse und Struktur hängt von Ihrer Verwendung ab. (ZB in Operationen, greifen Sie nur auf Teile der Struktur zu? Machen Sie eine Menge temporäres Kopieren? Wenn die Struktur klein ist, ist es wahrscheinlich immer besser zu verwenden, aber wenn sie groß ist, kann das Erstellen temporärer Kopien Sie verlangsamen mach es unveränderlich, du musst immer das ganze Ding kopieren, um den Wert zu ändern.)

Im Zweifelsfall messen.

Da Sie an möglichen Langzeitwirkungen interessiert sind, die bei einer solchen Messung möglicherweise nicht erkennbar sind, sollten Sie beachten, dass solche Arrays wahrscheinlich auf dem Heap mit großen Objekten gespeichert werden und wiederverwendet werden sollten. zugeordnet. (siehe CRL Inside Out: Large Object Heap Uncovered.)

Wenn Sie größere Strukturen in Aufrufen übergeben, können Sie sie mit dem Argument ref übergeben, um das Kopieren zu vermeiden.