Nahezu alle Ressourcen im Zusammenhang mit der Spielprogrammierung, insbesondere 3D-Open-World-Spiele, sprechen darüber, wie Sie ständig Assets auf und von Festplatte, Systemspeicher und Videospeicher entladen und neu laden müssen. Ich kann dies auf Konsolen verstehen, da sie sehr einfache Speicherverwaltungsschemata haben, die keinen möglichen Überlauf bewältigen können.
Auf dem PC ist die Situation jedoch ganz anders. Das Betriebssystem stellt virtuellen Speicher für den Systemspeicher bereit, und der Grafiktreiber übernimmt das Hin- und Herwechseln von der CPU zur GPU. Warum reicht es also nicht aus, alles auf einmal zu laden und sich nur mit dem Vorabrufen zu befassen und möglicherweise sicherzustellen, dass es keine Blockierung gibt, während ein erforderliches Asset ausgetauscht wird?
Das soll nicht heißen, dass alles mit so etwas naiv zugeordnet wird malloc
. Alles wird zusammenhängend und cache-kohärent gehalten. Es ist wohl einfacher, Ihren Speicherzugriff effizient zu gestalten, wenn Sie sich sowieso nicht um das manuelle Ein- und Ausblättern kümmern müssen ...
AKTUALISIEREN:
Nachdem ich ein wenig in asynchrone Pufferübertragungen gelesen habe , komme ich auf die Idee, dass die Art und Weise, wie der Grafiktreiber den Speicher automatisch ein- und ausblättern kann, nicht optimal ist. Gilt dies auch für CPU-Ressourcen? Ist es besser, immer manuell zu verwalten, wann eine bestimmte Ressource auch bei vorhandenem virtuellem Speicher geladen und entladen werden soll?
quelle
Antworten:
Moderne Open-World-Spiele passen einfach nicht in den Speicher. Beachten Sie, dass die meisten Spiele aufgrund der Anzahl der Spieler mit 32-Bit-Betriebssystemen immer noch 32-Bit sind und ein 32-Bit-Prozess höchstens 4 GB adressierten Speicher gleichzeitig haben kann (unabhängig vom virtuellen Speicher), dies jedoch realistisch ist begrenzt auf 2-3 GB. Die Fragmentierung und die tatsächliche Anzahl verwendbarer Objekte, die Sie gleichzeitig in einem Speicher haben können, sind ein gutes Stück kleiner als die Gesamtdaten, die Sie für eine große Umgebung benötigen. Selbst unter einem 64-Bit-Betriebssystem müssen Sie häufig auf Computer mit niedrigen Spezifikationen und nur 4 GB Arbeitsspeicher abzielen, um maximale Endbenutzerkompatibilität zu gewährleisten. Vergessen wir nicht mobile Geräte, "unterversorgte" Hardware wie die WiiU usw. Entwickler müssen viel mehr als nur große, ausgefallene Gaming-PC-Rigs ins Visier nehmen.
Virtueller Speicher ist keine Lösung, zum einen, weil er die Adressraumbeschränkungen nicht aufhebt und auch nicht optimal ist. Das Betriebssystem kann Dinge zu unpassenden Zeiten oder auf unpassende Weise ausblenden. Dies war ein Problem, mit dem sich die Betriebssysteme befassten, als der Winterschlaf zum ersten Mal auftrat. Das Auslagern der Prozesse auf die Festplatte und das anschließende Auslagern der Prozesse war in einigen Fällen erheblich langsamer als das explizite Streamen der Ressource durch die Anwendung. Sie können die Probleme auch heute noch sehen, wenn einem System der Speicher ausgeht und Seiten ausgelagert werden Festplatte, und das System reagiert nicht mehr. Kritische Dinge, die zum Ausführen Ihrer WM / explorer.exe erforderlich sind, werden ausgelagert. Der virtuelle Speicher war eine Lösung für ein Problem, bei dem Systeme vor Jahrzehnten nur sehr wenig RAM hatten und die Lücke zwischen Speicher- und Festplattengeschwindigkeit viel kleiner war. Auch heute noch' Die schnellsten SSDs machen nur einen winzigen Bruchteil der Geschwindigkeit von billigem / langsamem RAM aus, und es ist einfach nicht mehr die beste Idee, so zu tun, als könnten Sie Ihre Festplatte als virtuellen RAM verwenden. Dies ist ein Zeitalter, in dem einige Leute das Gegenteil tun und Dateisysteme auf RAM-Festplatten laden. Die Einschränkungen, die zur Erstellung des virtuellen Speichers geführt haben, gelten nicht mehr.
Abgesehen von Festplattenproblemen ist die benutzerdefinierte Ressourcenverwaltung immer noch ein wichtiger Bestandteil der Spieleentwicklung. Vom Debuggen von Hooks über Fragmentierungsprobleme bis hin zum intelligenten Streaming komplexer Ressourcen ist es nicht realistisch, einfach so zu tun, als wäre die ganze Welt eine unendlich große Schachtel mit Bits.
quelle
Bei einem 32-Bit-Spiel, wie die meisten Spiele aus verschiedenen Gründen, enthält selbst ein Spiel, das auf einer einseitigen DVD (4,3 GB) geliefert wird, bereits weitaus mehr Inhalte, die in einen 32-Bit-Adressraum eingepasst werden können. Und das setzt voraus, dass der Inhalt nicht auf Disc komprimiert ist, und lädt alles auf einmal in einen zusammenhängenden Adressraum-Ansatz. Viele Spiele werden jetzt auf mehreren DVDs geliefert und übertreffen leicht 10 GB Inhalt. Nach meiner Erfahrung auf dem PC schlägt die Zuweisung von 2 GB fehl, sobald sich Ihr Adressraum nähert. Dies wird zu einer harten Grenze, unabhängig davon, wie viel physischer Speicher der Benutzer hat.
Wenn Sie den Sprung auf 64-Bit machen, vorausgesetzt, Ihre Engine unterstützt ihn, verschwindet dieses harte Limit und wird durch ein effektives weiches Limit ersetzt. Sobald der Austausch des virtuellen Speichers beginnt, sinkt die Leistung des Spiels inakzeptabel. Wenn der Hauptprozess jemals warten muss, bis der Speicher wieder eingelagert wird, ruckelt und stört die Bildrate. Der virtuelle Speicher macht dies möglicherweise transparent, macht es jedoch nicht performant. Es braucht physisch Zeit, um diesen Speicher von der Festplatte zurückzubekommen, und während Sie warten, ist Ihr Spiel ins Stocken geraten. Es ist zwar möglich, das Problem zu umgehen (mit dem Vorabrufen von Speicherseiten im Hintergrund, von dem Sie wissen, dass Sie es bald benötigen), aber es ist ein schwieriger und unzuverlässiger Prozess, der dennoch Auswirkungen auf die Leistung hat.
Die Algorithmen des Betriebssystems zur Entscheidung, welche Seiten auf die Festplatte ausgetauscht werden sollen, kennen Ihr Spiel nicht und was es wahrscheinlich als nächstes benötigt. Darüber hinaus muss das Betriebssystem weiterhin andere Anwendungen unterstützen, die gleichzeitig mit Ihrem Spiel ausgeführt werden, sowie das Betriebssystem selbst. Das Anhalten, während Seiten von der Festplatte zurückgegeben werden, ist ein massiver Leistungseinbruch, und es spielt keine Rolle, ob es Ihr Spiel, eine andere Anwendung oder das Betriebssystem ist, das die Leistung des Spiels massiv beeinträchtigt.
Unabhängig davon, ob das Speicherlimit weich oder hart ist, ist der Speicher immer noch begrenzt. Aber selbst wenn Sie einfach alles auf einmal laden könnten, ohne eine Leistungsgrenze zu erreichen, gibt es immer noch Gründe, warum Sie nicht möchten:
Das Laden Ihres Spiels dauert viel länger als nötig, da es einfach alles zu Beginn lädt und es resident hält. Sie können ungefähr 150 MB / s von einer Festplatte laden, und selbst das schnellste DVD-Laufwerk (24x) wird mit 33 MB / s geladen. Das bedeutet, dass das Laden von Beispielinhalten mit 4,3 GB DVD mindestens 30 Sekunden und das Laden von DVD über 133 Sekunden dauert. Das sind unannehmbar lange Ladezeiten.
Ihr Spiel benötigt viel mehr Speicher als gerechtfertigt. Wenn nur 10% des Inhalts gleichzeitig sichtbar sind, ist es einfach verschwenderisch, den Rest resident zu halten, und verhindert, dass der Benutzer diesen Speicher für etwas anderes verwendet. Benutzer verzeihen Spiele im Allgemeinen nicht, für deren ordnungsgemäße Ausführung unverhältnismäßig viel Speicher erforderlich ist.
Durch das dynamische Streaming von Assets von der Festplatte, sei es im Hintergrund oder synchron während eines Ladebildschirms, können Sie den Arbeitsspeicher mit vernachlässigbarem Aufwand und nur einem geringen Nachteil für den Benutzer weitaus effizienter nutzen. Aber es ist eine Optimierung, und wie bei jeder anderen Optimierung nimmt die Rendite ab, je mehr Sie versuchen, sie anzuwenden. Irgendwann wird die Zunahme des Speicherbedarfs für die Aufbewahrung eines Objekts durch die Vorteile aufgewogen, die sich daraus ergeben, dass es dort vorhanden ist, ohne dass es geladen werden muss. Aber bis dieser Punkt erreicht ist, ist es besser, nur das zu laden, was Sie brauchen, wenn Sie es brauchen.
quelle
Nur sehr allgemein und vereinfacht gesagt, und ohne die Details von Implementierungen des virtuellen Speichers zu berücksichtigen, hat der Entwickler immer vorausschauendes Wissen, das der VM-Implementierung fehlt.
Der Entwickler kann immer sagen: "Ich muss diese Audiodatei jetzt nicht laden. Die Musik im Inneren wird nur für das Spiel über dem Bildschirm verwendet." Und unmittelbar nach dem Spiel über dem Bildschirm kann der Entwickler sagen: "Ich brauche diesen Audioclip nicht mehr im physischen Speicher. Er wird nur für dieses Spiel über dem Bildschirm verwendet."
Das Betriebssystem hat keine solche Voraussicht. Viele Seitenfehler später können möglicherweise feststellen, dass ein Audioclip im physischen Speicher nicht mehr benötigt wird, da seit einiger Zeit nicht mehr darauf zugegriffen wurde. Vorausschau in Rückblick umzuwandeln, führt jedoch zu vielen Seitenfehlern, und viele Seitenfehler führen zu Schluckauf bei den Bildraten in einer Software, die so zeitkritisch ist wie ein Videospiel. Dort hilft die Weitsicht des Entwicklers wirklich, wenn Sie solche Schluckaufe vermeiden wollen.
Und das gilt konzeptionell unabhängig von Hardware und Software. Angenommen, Paging im Speicher ist teuer, hilft die Voraussicht des Entwicklers immer dabei, diese Kosten zu senken.
Noch weiter gefasst gibt es einen nie endenden Zyklus zwischen Hardware-Designer, Compiler-Designer, OS / Treiber-Designer und Anwendungsentwickler. Die Entwickler von Hardware / Compiler / Betriebssystem / Treiber versuchen häufig, Optimierungen zu implementieren, um Ihre durchschnittliche Anwendung basierend auf den üblichen Speicherzugriffsmustern zu beschleunigen, und vielleicht manchmal mit der Hoffnung: "Die Leute sollten nur in der Lage sein, Code zu schreiben, wie sie wollen und es sollte schnell sein. "Wenn jedoch an diesen Typ gedacht wurde, schlägt er normalerweise für leistungskritische Felder fehl, da die leistungskritischen Entwickler dann die komplizierten Details ihres Compilers, ihrer Hardware, ihres Betriebssystems, ihrer Treiber usw. lernen und Code speziell schreiben Entwickelt, um dies so weit wie möglich auszunutzen, um den schnellstmöglichen Code zu schreiben (wie Prefetches, Aufteilen von Hot- / Cold-Feldern, SoAs usw. für cachefreundlichen Code). Und das ist wie ein Spiel, das niemals endet. Diese Dinge werden in leistungskritischen Bereichen niemals als Black Box behandelt, da die Entwickler um Leistung konkurrieren.
Persönlich wünschte ich mir, es gäbe keinen virtuellen Speicher, da er eine zusätzliche Ebene der Unvorhersehbarkeit der Leistung auf eine Weise hinzufügt, die zu extrem ist und viel zu viel Leistungseinbußen verursacht, wenn die Dinge wirklich nach Süden gehen und unbrauchbar werden. Ich bin manchmal auf Fälle gestoßen, in denen ich eine Anwendung verwendet habe, bei der ich versehentlich ein oder zwei zusätzliche Ziffern eingegeben habe, als ich in ein Eingabefeld getrunken habe, wodurch der physische Speicher so schnell erschöpft wurde, dass das Betriebssystem zu einem Crawl kam, bei dem ich nicht konnte. Klicken Sie nicht einmal mehr auf die Schaltfläche Abbrechen in der Fortschrittsanzeige und müssen Sie 10 Minuten warten, während Sie Strg + Alt + Entf drücken, um einen Vorgang abzubrechen, und verfluchen Sie mich, während Sie mein Getränk verschütten, um zu einem Punkt zurückzukehren, an dem die Dinge wieder verwendbar sind wurde trotz der Auslagerung der Auslagerungsdatei auf einer SSD. In diesen Fällen hätte ich lieber einen Fehler "Nicht genügend Speicher" oder so etwas vorgezogen. An diesem Punkt könnte ich einige meiner 17 Tabs mit Pornos schließen (es ist in Ordnung, ich setze trotzdem ein Lesezeichen für meine Favoriten), um Speicher freizugeben und dann sofort loszulegen Wiederaufnahme meines Geschäfts.
quelle