Jede Iteration jeder "foreach" -Schleife erzeugte 24 Bytes Müllspeicher?

7

Mein Freund arbeitet mit Unity3D auf C #. Und er sagte mir ausdrücklich:

  

Jede Iteration jeder "foreach" -Schleife erzeugte 24 Bytes Müll   Speicher.

Und ich sehe auch diese Information hier

Aber ist das wahr?

Der für meine Frage relevanteste Absatz:

  

Ersetzen Sie die "foreach" -Schleifen durch einfache "for" -Schleifen. Aus irgendeinem Grund,   Jede Iteration jeder "foreach" -Schleife erzeugte 24 Bytes Müll   Erinnerung. Eine einfache Schleife, die 10 Mal iterierte, ließ 240 Bytes Speicher übrig   bereit, gesammelt zu werden, was einfach inakzeptabel war

    
jimpanzer 10.09.2013, 11:59
quelle

3 Antworten

11

foreach ist ein interessantes Biest; Viele Leute glauben fälschlicherweise, dass es an IEnumerable[<T>] / IEnumerator[<T>] gebunden ist, aber das ist einfach nicht der Fall. Daher ist es sinnlos zu sagen:

  

Jede Iteration jeder "foreach" -Schleife erzeugte 24 Bytes Müllspeicher.

Insbesondere hängt es genau davon ab, was Sie durchlaufen. Zum Beispiel haben viele Typen benutzerdefinierte Iteratoren - List<T> zum Beispiel - hat einen struct -basierten Iterator. Folgendes weist null Objekte zu:

%Vor%

Allerdings tut dieser Objektzuweisungen:

%Vor%

Was identisch aussieht, aber nicht - indem wir die foreach auf IList<SomeType> iterieren (die keine benutzerdefinierte GetEnumerator() -Methode hat, die aber IEnumerable<SomeType> implementiert), zwingen wir sie zu verwenden die IEnumerable[<T>] / IEnumerator<T> API, die notwendigerweise ein Objekt involviert.

Bearbeiten caveat: Anmerkung Ich gehe hier davon aus, dass die Einheit die Werttyp-Semantik des benutzerdefinierten Iterators beibehalten kann. Wenn die Einheit gezwungen ist, Strukturen zu Objekten zu erheben, dann sind alle Wetten offen.

Wie auch immer, ich würde gerne sagen "sicher, verwenden for und ein Indexer in diesem Fall", wenn jede Zuteilung von Bedeutung ist, aber grundsätzlich: eine pauschale Aussage über foreach ist nicht hilfreich und irreführend.

    
Marc Gravell 10.09.2013, 12:20
quelle
10

Ihr Freund ist korrekt, der folgende Code wird 24k Müll pro Frame in Unity ab Version 4.3.4 generieren:

%Vor%

Dies zeigt die Zuweisung im Unity-Profiler:

Laut dem folgenden Link ist es ein Fehler in der Version von mono, die von Unity verwendet wird, dass der Struct-Enumerator geboxt wird. Das scheint eine vernünftige Erklärung zu sein, obwohl ich nicht durch Code-Inspektion verifiziert habe: Blog-Post diskutiert den Box-Bug

    
Chris Blackwell 25.03.2014 17:42
quelle
5

Es gibt hier einige gute Ratschläge bezüglich foreach, aber ich muss über den Kommentar des Marks, der sich auf Tags bezieht (ich habe leider nicht genügend Rep, um unter seinem Kommentar zu kommentieren) zu plappern, wo er sagte:

>
  

Eigentlich muss ich diesen Artikel mit einer Prise Salz nehmen, weil es so ist   Ansprüche "Aufruf der Tag-Eigenschaft für ein Objekt zuweist und kopiert   zusätzlicher Speicher "- wo Tag hier ist eine Zeichenfolge - sorry, aber das   einfach ist nicht wahr - alles was passiert ist, dass der Verweis auf die   Das vorhandene String-Objekt wird auf den Stack kopiert - es gibt kein Extra   Objektverteilung hier. -

Tatsächlich ruft das Aufrufen der Tag-Eigenschaft Müll hervor. Meine Vermutung ist, dass intern die Tags als Ganzzahlen (oder ein anderer einfacher Typ) gespeichert werden, und wenn die Tag-Eigenschaft aufgerufen wird, konvertiert Unity das int in eine Zeichenfolge unter Verwendung einer internen Tabelle.

Es widerspricht der Vernunft, da die tag -Eigenschaft genauso gut die Zeichenfolge aus dieser internen Tabelle zurückgeben kann, anstatt eine neue Zeichenfolge zu erstellen, aber aus welchem ​​Grund auch immer, so funktioniert es.

Sie können dies selbst mit der folgenden einfachen Komponente testen:

%Vor%

Wenn gameObject.tag keinen Müll produzierte, hätte das Erhöhen / Verringern der Anzahl der Iterationen keine Auswirkung auf die GC-Zuweisung (im Unity Profiler). Tatsächlich sehen wir einen linearen Anstieg der GC-Allocation, wenn die Anzahl der Iterationen zunimmt.

Bemerkenswert ist auch, dass sich die Namenseigenschaft auf genau die gleiche Weise verhält (wiederum der Grund, warum sich mir entzieht).

    
Kyle G 15.02.2014 05:16
quelle