Diese Frage wird bei Stack Overflow besser gestellt, da es wenig Spezifisches gibt, was Spiele betrifft.
Chris Garrett
31
@ Chris: Stimme überhaupt nicht zu: Die Frage bezieht sich speziell auf Spiele! Die Probleme, auf die Sie stoßen, wenn Sie alle 16 ms ein Update durchführen müssen, unterscheiden sich stark von den Problemen, die Sie in den meisten Desktop-Anwendungen haben.
Andrew Russell
Die Frage ist ziemlich unklar. Java und C # unterscheiden sich genug, damit nur sehr allgemeine Ratschläge für beide gelten. Alle Antworten waren bisher C #. Ebenfalls nicht erwähnte Zielplattform - gute Ratschläge können je nach Gerät unterschiedlich sein (z. B. Programmierung für ein Mobiltelefon, Zune, Xbox, anders als Programmierung für einen PC). Es ist sogar eine Frage, die weit genug reicht, dass jemand geantwortet hat, dass verwaltete Sprachen selbst die "Falle" sind.
Paulecoyote
@paulecoyote: Ich habe auf Frage umgestellt, um nur nach C # zu fragen. Da es keine bestimmte Plattform gibt, geht es auch um den PC.
Michael Klement
@Michaels Annahme, dass die Plattform eine gefährliche Annahme ist, da sie sich in der Implementierung so stark unterscheiden, wäre es gut, Windows spezifisch zu erwähnen und "like" und "Java" insgesamt wegzulassen.
Paulecoyote
Antworten:
69
Ich weiß nicht viel über Java, also ist dies aus der Sicht eines .net-Entwicklers.
Das mit Abstand größte ist Müll. Die .net-Müllabfuhr unter Windows leistet fantastische Arbeit, und Sie können weitestgehend ohne Babysitting davonkommen. Auf der xbox / winPhone7 ist das eine andere Sache. Wenn Sie alle paar Frames blockieren, kann die Garbage Collection zu Problemen führen. Im Moment wird es nach jeder Zuweisung von 1 MB ausgelöst.
Hier ein paar Tipps zum Umgang mit Müll. Sie sollten sich über die meisten dieser Probleme in der Realität keine Gedanken machen müssen, aber sie könnten sich eines Tages als nützlich erweisen.
Zeichnen Sie den Inhalt GC.GetTotalMemory()auf den Bildschirm. Dies gibt Ihnen einen ungefähren Überblick über die Menge der zugewiesenen Bytes, die Ihr Spiel verwendet. Wenn es sich kaum bewegt, geht es dir gut. Wenn es schnell geht, haben Sie Probleme.
Versuchen Sie, alle Ihre Heap- Objekte im Voraus zuzuweisen . Wenn Sie nicht alles vor Spielbeginn zuweisen, werden Sie jedes Mal zum Stillstand kommen, wenn Sie eine Vielzahl von Zuweisungen treffen. Keine Zuordnungen, keine Sammlungen. So einfach ist das.
Rufen Sie nach dem Laden GC.Collect () auf. Wenn Sie wissen, dass die meisten Ihrer großen Zuweisungen aus dem Weg sind, ist es nur nett, das System darüber zu informieren.
RUFEN SIE NICHT GC.Collect()jeden Frame an. Es mag wie eine gute Idee erscheinen, den Überblick über Ihren Müll zu behalten, aber denken Sie daran, dass das Einzige, was schlimmer ist als eine Müllsammlung, die Müllsammlung ist vorbei.
Achten Sie darauf, woher Ihr Müll kommt. Es gibt einige häufige Ursachen, z. B. das Verketten von Zeichenfolgen anstelle der Verwendung StringBuilder(Vorsicht, StringBuilderist kein Wundermittel und kann trotzdem Zuweisungen verursachen! ) Oder Das Verwenden von foreachSchleifen über Sammlungen, die die IEnumerableSchnittstelle verwenden, kann auch ohne Ihr Wissen zu Datenmüll führen (dies ist beispielsweise foreach (EffectPass pass in effect.CurrentTechnique.Passes)häufig der Fall).
Verwenden Sie Tools wie den CLR-Speicherprofiler, um herauszufinden, wo Speicher zugewiesen wird. Es gibt unzählige Tutorials zur Verwendung dieses Tools.
Wenn Sie wissen, wo Ihre Zuweisung während des Spiels erfolgt, versuchen Sie, mithilfe von Tricks wie dem Zusammenlegen von Objekten die Zuweisungsanzahl zu senken.
Wenn alles andere fehlschlägt, lassen Sie Ihre Sammlungen schneller laufen! Der GC auf dem kompakten Framework folgt jedem Verweis in Ihrem Code, um herauszufinden, welche Objekte nicht mehr verwendet werden. Refactor Ihren Code verwenden Sie weniger Referenzen!
Denken Sie daran, IDisposablefür Klassen zu verwenden, die nicht verwaltete Ressourcen enthalten. Sie können diese verwenden, um den Speicher zu bereinigen, den der GC nicht selbst freigeben kann.
Das andere, worüber man nachdenken sollte, ist die Gleitkomma-Performance. Der .Net JITer führt zwar eine ganze Reihe prozessorspezifischer Optimierungen durch, kann jedoch weder SSE noch andere SIMD-Befehlssätze verwenden, um die Gleitkomma-Mathematik zu beschleunigen. Dies kann bei Spielen zu einem großen Geschwindigkeitsunterschied zwischen C ++ und C # führen. Wenn Sie Mono verwenden, verfügen diese über einige spezielle SIMD-Mathematikbibliotheken, die Sie nutzen können.
Stimme voll und ganz zu. Die Garbage Collector-Implementierungen auf den "kleineren" Plattformen scheinen kompletter Müll zu sein.
Krisc
Guter Beitrag, aber im Hinblick auf Ihre Aussage über "Zuweisen von Heap-Objekten im Voraus" empfehle ich, die Wahrheit über Werttypen
Justin
Toller Punkt, wenn Sie Code optimieren, ist es wirklich wert, die Plattform zu verstehen, für die Sie optimieren möchten. Das war kein wirklicher Kommentar zu Werttypen / Referenztypen. Es ist unwahrscheinlich, dass sich ein langlebiges Objekt auf dem Stapel befindet. Es geht wirklich darum sicherzustellen, dass Sie so viel wie möglich von Ihren Zuweisungen zum Zeitpunkt des Ladens erledigen, damit Sie diese magische 1-MB-Barriere während des Spiels nicht überschreiten. Alle .net-Implementierungen, auf die xna abzielt, haben ebenfalls eine gute Garantie. Objekte, die zeitlich eng beieinander liegen, sind räumlich eng beieinander, was für die Perfektion hilfreich sein kann.
Cubed2D
Außerdem habe ich vergessen zu erwähnen, dass das aktuelle kompakte Framework auf der Xbox allergisch gegen Inline-Methodenaufrufe ist. Behalten Sie diese für Ihre Worst-Case-Szenarien bei, da die ref-Versionen der mathematischen Methoden so hässlich genug aussehen!
Cubed2D
10
Eine typische Leistungsfalle ist, dass der Müllsammler bei der Gestaltung / Entwicklung des Spiels nicht berücksichtigt wird. Das Produzieren von zu viel Müll kann zu "Schluckauf" im Spiel führen, was passiert, wenn der GC über eine beträchtliche Zeitspanne läuft.
Bei C # können die Verwendung von Wertobjekten und die Anweisung "using" den Druck durch den GC verringern.
Außerdem können Sie den Garbage Collector anweisen, explizit ausgeführt zu werden, wenn Sie gerade eine allokierte / freie schwere Schleife beendet haben oder wenn Sie feststellen, dass Sie freie Zyklen haben.
BarrettJ
16
Die usingAussage hat nichts mit Garbage Collection zu tun! Es ist für IDisposableObjekte gedacht, mit denen nicht verwaltete Ressourcen freigegeben werden (dh für Objekte, die nicht vom Garbage Collector verwaltet werden ).
Andrew Russell
9
Ich würde sagen, das größte Problem beim Schreiben von Spielen in C # war das Fehlen anständiger Bibliotheken. Die meisten, die ich gefunden habe, sind entweder direkte, aber unvollständige Ports oder Wrapper über eine C ++ - Bibliothek, die einen hohen Leistungsverlust für das Marshalling verursachen. (Ich spreche speziell über MOgre und Axiom für die OGRE-Bibliothek und BulletSharp für die Bullet-Physikbibliothek.)
Verwaltete Sprachen (anders als interpretiert - weder Java noch C # werden tatsächlich interpretiert) können genauso schnell sein wie Muttersprachen, wenn Sie genau wissen, was sie tatsächlich verlangsamt (Marshalling, Garbage Collection). Ich denke, das eigentliche Problem ist, dass Bibliotheksentwickler das noch nicht erkannt haben.
Das ist ein guter Punkt, wenn C # und Java verwaltet werden, anstatt interpretiert zu werden. Ich habe meine Frage bearbeitet, um sie genauer zu machen :)
Michael Klement
2
Marshalling ist im Allgemeinen ein Leistungsengpass, aber es hilft auch, sich über blittbare Typen im Klaren zu sein - Typen, die direkt auf nicht verwalteten Speicher abgebildet werden können, ohne dass die Leistung erheblich beeinträchtigt wird. msdn.microsoft.com/en-us/library/75dwhxf7.aspx
Sean Edwards
8
Wie bereits erwähnt, sind GC-Erfassungspausen das größte Problem. Die Verwendung von Objektpools ist eine typische Lösung.
C # und Java werden nicht interpretiert. Sie werden zu einem Zwischenbytecode kompiliert, der nach JIT genauso schnell wird wie nativer Code (oder so gut wie bedeutungslos ist).
Die größte Gefahr, die ich gefunden habe, besteht darin, Ressourcen freizugeben, die sich direkt auf die Benutzererfahrung auswirken. Diese Sprachen unterstützen nicht automatisch die deterministische Finalisierung wie C ++. Wenn Sie dies nicht erwarten, kann dies dazu führen, dass in der Szene Meshes schweben, nachdem Sie dachten, dass sie zerstört wurden. (C # führt eine deterministische Finalisierung durch IDisposable durch . Ich bin mir nicht sicher, was Java tut.)
Davon abgesehen sind verwaltete Sprachen in der Lage, die Leistung, die Spiele erfordern, um einiges besser zu bewältigen, als es ihnen zugetraut wird. Gut geschriebener verwalteter Code ist viel schneller als schlecht geschriebener nativer Code.
Yeah, danke für den Hinweis, der die interpretierte / verwaltete Sache bereits korrigiert hat;) Auch ein guter Punkt, wenn die Maschen durch die Szene schweben. Ich habe nicht daran gedacht, als ich über GC-Probleme
Michael Klement
1
IDisposableErmöglicht die deterministische Bereinigung zeitkritischer und nicht verwalteter Ressourcen, wirkt sich jedoch nicht direkt auf die Finalisierung oder den Garbage Collector aus.
Sam Harwell
4
Weder Java noch C # werden interpretiert. Beide werden in nativen Maschinencode kompiliert.
Das größte Problem bei beiden und den Spielen ist, dass sie so codieren müssen, dass sie während des Spiels niemals Müll sammeln. Die Anzahl der Reifen, durch die Sie springen müssen, um dies zu erreichen, überwiegt fast die Vorteile der ersten Verwendung. Die meisten Funktionen, mit denen die Verwendung dieser Sprache für die Programmierung von Anwendungen oder Servern Spaß macht, müssen für die Spielprogrammierung vermieden werden, da es sonst zu langen Pausen während des Spiels kommt, wenn die Sprachen losgehen und Müll sammeln.
Mit Garbage Collection kann man sich zumindest in C # einigermaßen gut auseinandersetzen, daher würde ich nicht sagen, dass es ein Deal-Breaker ist. Mit dem richtigen Threading und der Kenntnis des Programmstatus können Sie Leistungsprobleme vermeiden. Es ist noch eine andere Sache, über die Sie nachdenken müssen, und es macht die verwaltete Sprache ein wenig weniger verwaltet.
Karantza
4
In .NET 4 unterstützt der Garbage Collector die Hintergrunderfassung für alle drei Generationen von Objekten. Dies sollte die Auswirkungen der Speicherbereinigung in Spielen auf die Leistung effektiv minimieren. Relevanter Link: geekswithblogs.net/sdorman/archive/2008/11/07/…
Mike Strobel
Müllsammler entwickeln sich weiter, und wie Mike Strobel feststellt, sind einige bereits in Produktion, die diese Gefahr beinahe ausräumen.
Sam Harwell
2
Weder C # noch Java werden zu systemeigenem Maschinencode kompiliert. C # kompiliert nach MSIL und Java nach Bytecode. Garbage Collection gibt keine "langen" Pausen, aber es kann "Schluckauf" geben.
Cloudanger
2
Eine große Gefahr, die ich beim Erstellen von Spielen mit solchen Sprachen (oder beim Verwenden von Tools wie XNA, TorqueX usw.) sehe, ist, dass es Ihnen schwer fallen wird, ein Team guter Leute mit dem Fachwissen zu finden, das erforderlich ist, um ein gleichwertiges Spiel zu erstellen Es wäre ziemlich einfach, Leute in C ++ und OpenGL / DirectX zu finden.
Die Spieleentwicklungsbranche ist immer noch sehr stark von C ++ geprägt, da die meisten Tools und Pipelines, mit denen große oder nur gut polierte kleine Spiele herausgepusht werden, in C ++ geschrieben wurden. Soweit ich weiß, gibt es ALLE offiziellen Entwickler-Kits, die Sie verwenden können Get für XBox, PS3 und Wii sind nur mit Kompatibilität für C ++ erhältlich (das XBox-Toolset kann heutzutage besser verwaltet werden, weiß jemand mehr?)
Wenn Sie Spiele für Konsolen entwickeln möchten, erhalten Sie XNA und C # auf der XBox und dann nur in einem Teil der Spielbibliothek namens XBox Live Indie Games. Einige, die Wettbewerbe usw. gewinnen, werden ausgewählt, um ihr Spiel auf die echte XBox Live Arcade zu portieren. Anders als dieser Plan, ein Spiel für den PC zu machen.
Antworten:
Ich weiß nicht viel über Java, also ist dies aus der Sicht eines .net-Entwicklers.
Das mit Abstand größte ist Müll. Die .net-Müllabfuhr unter Windows leistet fantastische Arbeit, und Sie können weitestgehend ohne Babysitting davonkommen. Auf der xbox / winPhone7 ist das eine andere Sache. Wenn Sie alle paar Frames blockieren, kann die Garbage Collection zu Problemen führen. Im Moment wird es nach jeder Zuweisung von 1 MB ausgelöst.
Hier ein paar Tipps zum Umgang mit Müll. Sie sollten sich über die meisten dieser Probleme in der Realität keine Gedanken machen müssen, aber sie könnten sich eines Tages als nützlich erweisen.
GC.GetTotalMemory()
auf den Bildschirm. Dies gibt Ihnen einen ungefähren Überblick über die Menge der zugewiesenen Bytes, die Ihr Spiel verwendet. Wenn es sich kaum bewegt, geht es dir gut. Wenn es schnell geht, haben Sie Probleme.GC.Collect()
jeden Frame an. Es mag wie eine gute Idee erscheinen, den Überblick über Ihren Müll zu behalten, aber denken Sie daran, dass das Einzige, was schlimmer ist als eine Müllsammlung, die Müllsammlung ist vorbei.StringBuilder
(Vorsicht,StringBuilder
ist kein Wundermittel und kann trotzdem Zuweisungen verursachen! ) Oder Das Verwenden vonforeach
Schleifen über Sammlungen, die dieIEnumerable
Schnittstelle verwenden, kann auch ohne Ihr Wissen zu Datenmüll führen (dies ist beispielsweiseforeach (EffectPass pass in effect.CurrentTechnique.Passes)
häufig der Fall).IDisposable
für Klassen zu verwenden, die nicht verwaltete Ressourcen enthalten. Sie können diese verwenden, um den Speicher zu bereinigen, den der GC nicht selbst freigeben kann.Das andere, worüber man nachdenken sollte, ist die Gleitkomma-Performance. Der .Net JITer führt zwar eine ganze Reihe prozessorspezifischer Optimierungen durch, kann jedoch weder SSE noch andere SIMD-Befehlssätze verwenden, um die Gleitkomma-Mathematik zu beschleunigen. Dies kann bei Spielen zu einem großen Geschwindigkeitsunterschied zwischen C ++ und C # führen. Wenn Sie Mono verwenden, verfügen diese über einige spezielle SIMD-Mathematikbibliotheken, die Sie nutzen können.
quelle
Eine typische Leistungsfalle ist, dass der Müllsammler bei der Gestaltung / Entwicklung des Spiels nicht berücksichtigt wird. Das Produzieren von zu viel Müll kann zu "Schluckauf" im Spiel führen, was passiert, wenn der GC über eine beträchtliche Zeitspanne läuft.
Bei C # können die Verwendung von Wertobjekten und die Anweisung "using" den Druck durch den GC verringern.
quelle
using
Aussage hat nichts mit Garbage Collection zu tun! Es ist fürIDisposable
Objekte gedacht, mit denen nicht verwaltete Ressourcen freigegeben werden (dh für Objekte, die nicht vom Garbage Collector verwaltet werden ).Ich würde sagen, das größte Problem beim Schreiben von Spielen in C # war das Fehlen anständiger Bibliotheken. Die meisten, die ich gefunden habe, sind entweder direkte, aber unvollständige Ports oder Wrapper über eine C ++ - Bibliothek, die einen hohen Leistungsverlust für das Marshalling verursachen. (Ich spreche speziell über MOgre und Axiom für die OGRE-Bibliothek und BulletSharp für die Bullet-Physikbibliothek.)
Verwaltete Sprachen (anders als interpretiert - weder Java noch C # werden tatsächlich interpretiert) können genauso schnell sein wie Muttersprachen, wenn Sie genau wissen, was sie tatsächlich verlangsamt (Marshalling, Garbage Collection). Ich denke, das eigentliche Problem ist, dass Bibliotheksentwickler das noch nicht erkannt haben.
quelle
Wie bereits erwähnt, sind GC-Erfassungspausen das größte Problem. Die Verwendung von Objektpools ist eine typische Lösung.
quelle
C # und Java werden nicht interpretiert. Sie werden zu einem Zwischenbytecode kompiliert, der nach JIT genauso schnell wird wie nativer Code (oder so gut wie bedeutungslos ist).
Die größte Gefahr, die ich gefunden habe, besteht darin, Ressourcen freizugeben, die sich direkt auf die Benutzererfahrung auswirken. Diese Sprachen unterstützen nicht automatisch die deterministische Finalisierung wie C ++. Wenn Sie dies nicht erwarten, kann dies dazu führen, dass in der Szene Meshes schweben, nachdem Sie dachten, dass sie zerstört wurden. (C # führt eine deterministische Finalisierung durch IDisposable durch . Ich bin mir nicht sicher, was Java tut.)
Davon abgesehen sind verwaltete Sprachen in der Lage, die Leistung, die Spiele erfordern, um einiges besser zu bewältigen, als es ihnen zugetraut wird. Gut geschriebener verwalteter Code ist viel schneller als schlecht geschriebener nativer Code.
quelle
IDisposable
Ermöglicht die deterministische Bereinigung zeitkritischer und nicht verwalteter Ressourcen, wirkt sich jedoch nicht direkt auf die Finalisierung oder den Garbage Collector aus.Weder Java noch C # werden interpretiert. Beide werden in nativen Maschinencode kompiliert.
Das größte Problem bei beiden und den Spielen ist, dass sie so codieren müssen, dass sie während des Spiels niemals Müll sammeln. Die Anzahl der Reifen, durch die Sie springen müssen, um dies zu erreichen, überwiegt fast die Vorteile der ersten Verwendung. Die meisten Funktionen, mit denen die Verwendung dieser Sprache für die Programmierung von Anwendungen oder Servern Spaß macht, müssen für die Spielprogrammierung vermieden werden, da es sonst zu langen Pausen während des Spiels kommt, wenn die Sprachen losgehen und Müll sammeln.
quelle
Eine große Gefahr, die ich beim Erstellen von Spielen mit solchen Sprachen (oder beim Verwenden von Tools wie XNA, TorqueX usw.) sehe, ist, dass es Ihnen schwer fallen wird, ein Team guter Leute mit dem Fachwissen zu finden, das erforderlich ist, um ein gleichwertiges Spiel zu erstellen Es wäre ziemlich einfach, Leute in C ++ und OpenGL / DirectX zu finden.
Die Spieleentwicklungsbranche ist immer noch sehr stark von C ++ geprägt, da die meisten Tools und Pipelines, mit denen große oder nur gut polierte kleine Spiele herausgepusht werden, in C ++ geschrieben wurden. Soweit ich weiß, gibt es ALLE offiziellen Entwickler-Kits, die Sie verwenden können Get für XBox, PS3 und Wii sind nur mit Kompatibilität für C ++ erhältlich (das XBox-Toolset kann heutzutage besser verwaltet werden, weiß jemand mehr?)
Wenn Sie Spiele für Konsolen entwickeln möchten, erhalten Sie XNA und C # auf der XBox und dann nur in einem Teil der Spielbibliothek namens XBox Live Indie Games. Einige, die Wettbewerbe usw. gewinnen, werden ausgewählt, um ihr Spiel auf die echte XBox Live Arcade zu portieren. Anders als dieser Plan, ein Spiel für den PC zu machen.
quelle