Diese Seite beschreibt häufige Leistungsprobleme und beste Praktiken zur Linderung dieser Probleme.
Skriptberechnung
Teure Operationen im Luau-Code dauern länger, um zu verarbeiten, und können somit die Bildrate beeinflussen.Es wird ausgeführt, es sei denn, es wird parallel ausgeführt, führt der Luau-Code synchron aus und blockiert den Haupt thread, bis er eine Funktion findet, die den Thread liefert.
Häufige Probleme
Intensive Operationen an Tabellenstrukturen - Komplexe Operationen wie Serienisierung, Deserialisierung und tiefe Klonung verursachen hohe Leistungskosten, insbesondere auf großen Tabellenstrukturen.Das gilt besonders, wenn diese Operationen rekursiv sind oder sich auf die Iteration über sehr große Datenstrukturen beziehen.
Häufige Ereignisse - Das Binden teurer Operationen an Frame-basierte Ereignisse von RunService ohne die Frequenz zu begrenzen, bedeutet, dass diese Operationen jeden Frame wiederholt werden, was oft zu einer unnötigen Erhöhung der Berechnungszeit führt.Diese Ereignisse beinhalten:
Abmildigung
- Beschwöre Code auf RunService Ereignissen sparsam, begrenze die Nutzung auf Fälle, in denen eine häufige Beschwörung unerlässlich ist (z. B. das Aktualisieren der Kamera).Du kannst den Großteil des anderen Codes in anderen Ereignissen oder seltener in einer Schleife ausführen.
- Teile große oder teure Aufgaben mit task.wait(), um die Arbeit auf mehrere Rahmen zu verteilen.
- Identifizieren und optimieren Sie unnötig teure Operationen und verwenden Sie Multithreading für kostenintensive Aufgaben, die nicht auf das Datenmodell zugreifen müssen
- Bestimmte serverseitige Skripte können von nativer Codegeneration profitieren, einer einfachen Flagge, die ein Skript in Maschinencode kompiliert, anstatt in Bytecode.
Mikroprofilierungs-Scopes
Umfang | Verknüpfte Berechnung |
LaufService.PreRender | Code wird beim PreRender-Ereignis ausgeführt |
LaufService.PreSimulation | Code wird beim Stepped-Ereignis ausgeführt |
LaufService.PostSimulation | Code wird beim Herzschlag-Ereignis ausgeführt |
RunService.Herzschlag | Code wird beim Herzschlag-Ereignis ausgeführt |
Für weitere Informationen zum Debuggen von Skripten mit dem MicroProfiler, siehe die debug Bibliothek, die Funktionen für das Markieren von spezifischem Code und die weitere Erhöhung der Spezifität enthält, wie debug.profilebegin und debug.profileend .Viele Roblox-API-Methoden, die von Skripten aufgerufen werden, haben auch eigene MicroProfiler-Tags, die nützliche Signale liefern können.
Skriptspeicherverwendung
Speicherlecks können auftreten, wenn Sie Skripte schreiben, die Speicher verbrauchen, den der Garbage-Collector nicht richtig freigeben kann, wenn er nicht mehr in Verwendung ist.Lecks sind speziell auf dem Server verbreitet, weil sie kontinuierlich für viele Tage online sein können, während eine Kunden-Sitzung viel kürzer ist.
Die folgenden Speicherwerte in der Entwicklerkonsole können ein Problem anzeigen, das weitere Untersuchungen erfordert:
- LuaHeap - Hohe oder wachsende Verbrauch zeigt auf einen Speicherleck hin
- Instanzanzahl - Konsistent wachsende Anzahl von Instanzen deutet darauf hin, dass sich keine Referenzen auf einige Instanzen in deinem Code nicht sammeln lassen.
- Platzskriptspeicher - Stellt ein Skript durch Skript-Aufteilung der Speicherverwendung bereit.
Häufige Probleme
Verbindungen offen lassen - Die Engine sammelt niemals Garbage-Events, die mit einer Instanz verbunden sind, und alle Werte, die innerhalb der verbundenen Rückrufe referenziert werden.Daher sind aktive Verbindungen von Ereignissen und Code innerhalb der verbundenen Instanzen, verbundenen Funktionen und referenzierten Werten für den Speicher-Garbage-Sammler außerhalb des Speicherbereichs, auch nachdem die Ereignisse abgefeuert wurden.
Obwohl Ereignisse getrennt sind, wenn die zugehörige Instanz zerstört wird, ist ein häufiger Fehler die Annahme, dass dies für Player Objekte gilt.Nachdem ein Benutzer ein Erlebnis verlässt, zerstört die Engine nicht automatisch sein repräsentatives Player Objekt und Charaktermodell, so dass Verbindungen zum Player Objekt und Instanzen unter dem Charaktermodell, wie Player.CharacterAdded, weiterhin Speicher verbrauchen, wenn Sie sie in Ihren Skripten nicht trennen.Dies kann zu sehr signifikanten Speicherlecks auf dem Server im Laufe der Zeit führen, wenn sich Hunderte von Benutzern der Erfahrung anschließen und sie verlassen.
Tabellen - Das Einfügen von Objekten in Tabellen, aber sie nicht zu entfernen, wenn sie nicht mehr benötigt werden, verursacht unnötigen Speicherverbrauch, insbesondere für Tabellen, die Benutzerdaten verfolgen, wenn sie sich zusammenschließen.Zum Beispiel erstellt das folgende Codebeispiel eine Tabelle, die jedes Mal Informationen über den Benutzer hinzufügt, wenn sich ein Benutzer anmeldet
Beispiellocal playerInfo = {}Players.PlayerAdded:Connect(function(player)playerInfo[player] = {} -- etwas informationend)Wenn Sie diese Einträge nicht entfernen, wenn sie nicht mehr benötigt werden, wächst die Tabelle weiter und verbraucht mehr Speicher, wenn mehr Benutzer der Sitzung beitreten.Jeder Code, der über diese Tabelle iteriert, wird auch teurer, wenn die Tabelle an Größe wächst.
Abmildigung
Um alle verwendeten Werte zu löschen, um Speicherlecks zu verhindern:
Trennen Sie alle Verbindungen - Gehen Sie durch Ihre Codebasis, um sicherzustellen, dass jede Verbindung über einen der folgenden Pfade gereinigt wird:
- Manuell trennen mit der Funktion Disconnect().
- Zerstörung der Instanz, zu der das Ereignis gehört, mit der Destroy()-Funktion.
- Zerstörung des Skriptobjekts, auf das die Verbindung zurückverfolgt wird.
Entferne Spielerobjekte und Charaktere nach dem Verlassen - Implementiere Code, um sicherzustellen, dass keine Verbindungen nach dem Verlassen eines Benutzers bestehen bleiben, wie im folgenden Beispiel:
BeispielPlayers.PlayerAdded:Connect(function(player)player.CharacterRemoving:Connect(function(character)task.defer(character.Destroy, character)end)end)Players.PlayerRemoving:Connect(function(player)task.defer(player.Destroy, player)end)
Physik-Berechnung
Übermäßige Physiksimulation kann eine wichtige Ursache für die Zunahme der Berechnungszeit pro Frame auf dem Server und dem Client sein.
Häufige Probleme
Übertriebene Physik-Zeitstufenfrequenz - Standardmäßig ist das Schrittverhalten im adaptiven Modus, wo Physikschritte entweder mit 60 Hz, 120 Hz oder 240 Hz ausgeführt werden, je nach Komplexität des physikalischen Mechanismus.
Es ist auch ein fester Modus mit verbesserter Genauigkeit der Physik verfügbar, der alle Physik-Assemblys zwingt, bei 240 Hz (viermal pro Frame) zu treten.Dies führt zu deutlich mehr Berechnung pro Frame.
Übertriebene Anzahl der Komplexität simulierter Objekte - Je mehr 3D-Montagen simuliert werden, desto länger dauern die physikalischen Berechnungen pro Frame.Oft werden Erlebnisse Objekte haben, die simuliert werden, die nicht sein müssen oder Mechanismen haben, die mehr Einschränkungen und Gelenke haben als sie brauchen.
Übermäßig präzise Kollisionserkennung - Netzwerkteile haben ein CollisionFidelity Eigenschaft zum Erkennen von Kollisionen, die eine Vielzahl von Modi mit unterschiedlichen Leistungseffekten bietet.Der präzise Kollisionserkennungsmodus für Netzwerkteile hat die teuerste Leistungskosten und dauert länger, um zu berechnen.
Abmildigung
Ankerteile, die keine Simulation erfordern - Anker alle Teile, die nicht von der Physik angetrieben werden müssen, wie z. B. für statische NPCs.
Verwende adaptive Physik-Schritte - Adaptive Schritte passen die Geschwindigkeit der Physikberechnungen für physikalische Mechanismen dynamisch an, so dass Physikaktualisierungen in einigen Fällen weniger häufig durchgeführt werden können
Reduzieren Sie die Komplexität des Mechanismus * Wo immer möglich, minimiere die Anzahl der physikalischen Einschränkungen oder Gelenke in einer Montagemaschine.
- Reduziere die Menge an Selbstkollision innerhalb eines Mechanismus, z. B. durch die Anwendung von Grenzen oder No-Collision-Einschränkungen auf Ragdoll-Gliedmaßen, um sie vor dem Zusammenstoßen zu schützen.
Reduzieren Sie die Verwendung von präziser Kollisionsgenauigkeit für Meshes * Für kleine oder nicht interaktionsfähige Objekte, bei denen Benutzer selten den Unterschied bemerken würden, verwende Box-Treue.
Für kleinere bis mittlere Objekte verwende Box- oder Hulltreue, abhängig von der Form.
Für große und sehr komplexe Objekte bauen Sie benutzerdefinierte Kollisionen mit unsichtbaren Teilen aus, wenn möglich
Für Objekte, die keine Kollisionen erfordern, deaktivieren Sie Kollisionen und verwenden Sie Box- oder Hulltreue, da die Kollisionsgeometrie immer noch in der Speicher verwahrt wird.
Du kannst die Kollisionsgeometrie für Fehlerbehebungszwecke in Studio rendern, indem du auf Kollisionsgenauigkeit aus dem Widget Visualisierungsoptionen in der oberen rechten Ecke des 3D-Ansichtsfensters umschaltest.
Alternativ kannst du den CollisionFidelity = Precise Filter auf den Explorer anwenden, der eine Zählung aller Meshelemente mit der genauen Genauigkeit anzeigt und es dir ermöglicht, sie einfach auszuwählen.
Für einen ausführlichen Überblick darüber, wie man eine Kollisionsgenauigkeitsoption wählt, die die Präzisions- und Leistungsanforderungen ausgleicht, siehe Physik- und Render参数设置.
Mikroprofilierungs-Scopes
Umfang | Verknüpfte Berechnung |
physicsStepped | Gesamte Physikberechnung |
Weltschritt | Diskrete Physik-Schritte werden jeden Frame ausgeführt |
Physikspeicherverbrauch
Bewegung und Kollisionserkennung in der Physik verbrauchen Speicher.Mesh-Teile haben eine CollisionFidelity Eigenschaft, die die Art und Weise bestimmt, mit der die Kollisionsgrenzen des Meshes bewertet werden.
Häufiges Problem
Die Standard- und präzisen Kollisionserkennungsmodi verbrauchen deutlich mehr Speicher als die beiden anderen Modi mit niedrigerer Kollisionsgenauigkeit.
Wenn du hohe Niveaus des Speicherverbrauchs unter PhysicsParts siehst, musst du möglicherweise die Kollisionsgenauigkeit von Objekten in deiner Erfahrung reduzieren.
Wie man abfedert
Um die für die Kollisionssicherheit verwendete Speicher zu reduzieren:
- Für Teile, die keine Kollisionen benötigen, deaktivieren Sie ihre Kollisionen, indem Sie BasePart.CanCollide , BasePart.CanTouch und BasePart.CanQuery auf false setzen.
- Reduziere die Treffergenauigkeit von Kollisionen mit der Einstellung CollisionFidelity.Box hat den niedrigsten Speicherverbrauch, und Default und Precise sind im Allgemeinen teurer.
- Es ist in der Regel sicher, die Kollisionsfidelität eines kleinen angeankerten Teils auf Box zu setzen.
- Für sehr komplexe große Meshes möchten Sie vielleicht Ihr eigenes Kollisionsnetz aus kleineren Objekten mit Kistenkollisionsgenauigkeit erstellen.
Menschenoiden
Humanoid ist eine Klasse, die eine Vielzahl von Funktionen für Spieler- und Nicht-Spielercharaktere (NPCs) bereitstellt.Obwohl mächtig, kommt ein Humanoid mit einer erheblichen Berechnungskosten.
Häufige Probleme
- Alle HumanoidStateTypes auf NPCs aktiviert lassen - Es gibt eine Leistungskosten, wenn bestimmte HumanoidStateTypes aktiviert bleiben.Deaktivieren Sie alles, was für Ihre NPCs nicht benötigt wirdZum Beispiel ist es, wenn dein NPC keine Leitern klettern wird, sicher, den Zustand Climbing zu deaktivieren.
- Modelle mit Humanoiden häufig instantieren, modifizieren und respawnen * Dies kann intensiv für die Verarbeitung durch die Engine sein, insbesondere, wenn diese Modelle mehrschichtige Kleidung verwenden.Dies kann auch in Erlebnissen problematisch sein, in denen Avatare häufig respawnen.
- Im Mikroprofilierer werden lange updateInvalidedFastClusters -Tags (über 4 ms) oft zu einem Signal, dass die Avatar-Instanzierung/Modifikation übermäßige Invalidierungen auslöst.
- Verwendung von Humanoiden in Fällen, in denen sie nicht erforderlich sind - Statische NPCs, die sich im Allgemeinen nicht bewegen, haben keine Notwendigkeit für die Klasse Humanoid.
- Spielen von Animationen auf einer großen Anzahl von NPCs vom Server - NPC-Animationen, die auf dem Server ausgeführt werden, müssen auf dem Server simuliert und auf den Client repliziert werden.Dies kann unnötige Aufwendungen sein.
Abmildigung
- Spiele NPC-Animationen auf dem Client - In Erlebnissen mit einer großen Anzahl von NPCs, erwäge die Erstellung des Animator auf dem Client und die Ausführung der Animationen lokal.Dies reduziert die Belastung auf dem Server und die Notwendigkeit einer unnötigen Replikation.Es ermöglicht auch zusätzliche Optimierungen (z. B. nur Animationen für NPCs abspielen, die sich in der Nähe des Charakters befinden).
- Verwende leistungsfreundliche Alternativen zu Humanoids - NPC-Modelle müssen nicht unbedingt ein humanoides Objekt enthalten.
- Für statische NPCs verwende ein einfaches AnimationController, da sie sich nicht bewegen müssen, aber nur Animationen abspielen müssen.
- Für bewegliche NPCs, erwäge die Implementierung eines eigenen Bewegungscontrollers und die Verwendung eines AnimationController für Animationen, abhängig von der Komplexität deiner NPCs.
- Deaktiviere unbenutzte humanoide Zustände - Verwende Humanoid:SetStateEnabled(), um nur notwendige Zustände für jeden Humanoide zu aktivieren.
- Pool-NPC-Modelle mit häufigem Respawnen - Statt einen NPC vollständig zu zerstören, sende den NPC in einen Pool inaktiver NPCs.Auf diese Weise kannst du, wenn ein neuer NPC zum Respawnen benötigt wird, einfach einen der NPCs aus dem Pool reaktivieren.Dieser Prozess heißt Pooling, was die Anzahl der Zeiten minimiert, in denen Zeichen instanziert werden müssen.
- Spawne nur NPCs, wenn Benutzer in der Nähe sind - Spawne keine NPCs, wenn Benutzer nicht in Reichweite sind, und vernichte sie, wenn Benutzer ihre Reichweite verlassen.
- Vermeiden Sie Änderungen an der Avatar-Hierarchie, nachdem sie instanziiert wurde - Bestimmte Änderungen an einer Avatar-Hierarchie haben erhebliche Leistungseinschränkungen.Einige Optimierungen sind verfügbar:
- Für benutzerdefinierte prozedurale Animationen aktualisieren Sie nicht die Eigenschaften JointInstance.C0 und JointInstance.C1. Stattdessen aktualisieren Sie die Eigenschaft Motor6D.Transform.
- Wenn du BasePart Objekte an den Avatar anfügen musst, tue dies außerhalb der Hierarchie des Avatars Model.
Mikroprofilierungs-Scopes
Umfang | Verknüpfte Berechnung |
stepHumanoid | Humanoide Steuerung und Physik |
Schrittanimation | Humanoid- und Animator-Animation |
aktualisierenFehlendeSchnelleCluster | Verknüpft mit der Instanzierung oder Änderung eines Avatars |
Renderieren
Ein erheblicher Teil der Zeit, die der Client für jeden Frame ausgibt, ist mit der Rendering der Szene im aktuellen Frame verbunden.Der Server rendert nichts, also ist dieser Abschnitt exklusiv für den Client.
Ziehrufe ausladen
Ein Draw-Aufruf ist eine Reihe von Anweisungen von der Engine an die GPU, etwas zu rendern.Ziehaufrufe haben erhebliche Überschneidungen.Im Allgemeinen werden je weniger Ziehaufrufe pro Frame ausgeführt, desto weniger wird zur Darstellung eines Frames berechnete Zeit ausgegeben.
Du kannst sehen, wie viele Zeichnungsaufrufe derzeit mit dem Render Stats > Timing Artikel in Studio auftreten.Sie können Render-Statistiken anzeigen im Client durch Drücken von anzeigen .
Je mehr Objekte in deiner Szene in einem bestimmten Rahmen gezeichnet werden müssen, desto mehr GPU-Aufrufe werden getätigt.Die Roblox-Engine nutzt jedoch einen Prozess namens Instanziierung, um identische Meshes mit den gleichen Texturmerkmalen in eine einzige Draw-Aufruf zusammenzuführen.Genau genommen werden mehrere Meshes mit derselben MeshId in einer einzigen Zeichnungsanruf verwendet, wenn:
- SurfaceAppearances sind identisch. TextureIDs sind identisch, wenn SurfaceAppearance nicht existiert.
- Die Materialien sind identisch, wenn sowohl SurfaceAppearance als auch MeshPart.TextureID nicht existieren.
Andere häufige Probleme
Übertriebene Objektdichte - Wenn eine große Anzahl von Objekten mit hoher Dichte konzentriert ist, erfordert die Rendering dieses Bereichs der Szene mehr Zeichnungsbefehle.Wenn du deine Bildrate findest, wenn du dich auf einen bestimmten Teil der Karte bewegst, kann dies ein gutes Signal sein, dass die Objektdichte in diesem Bereich zu hoch ist.
Objekte wie Aufkleber, Texturen und Partikel werden nicht gut gebündelt und führen zu zusätzlichen Zeichnungsaufrufen.Achten Sie besonders auf diese Objektarten in einer Szene.Insbesondere können Eigenschaftsänderungen an ParticleEmitters eine dramatische Auswirkung auf die Leistung haben.
Versäumte Instanzierungsgelegenheiten - Häufig wird eine Szene die gleiche Mesh-ID mehrmals wiederholen, aber jede Kopie des Meshs hat unterschiedliche Mesh- oder Textur-Asset-IDs.Dies verhindert die Instanzierung und kann zu unnötigen Ziehaufrufen führen.
Eine häufige Ursache für dieses Problem ist, wenn eine ganze Szene auf einmal importiert wird, anstatt einzelne Assets in Roblox importiert und dann nach dem Import dupliziert werden, um die Szene zusammenzustellen.
Übertriebene Objektkomplexität - Obwohl es nicht so wichtig ist wie die Anzahl der Zeichnungsbefehle, beeinflusst die Anzahl der Dreieck in einer Szene, wie lange ein Frame zum Rendern braucht.Szenen mit einer sehr großen Anzahl sehr komplexer Meshes sind ein häufiges Problem, ebenso wie Szenen mit der Eigenschaft MeshPart.RenderFidelity mit zu vielen Meshes auf Enum.RenderFidelity.Precise gesetzt.
Übertriebene Schattenwurf - Das Handling von Schatten ist ein teurer Prozess, und Karten, die eine hohe Anzahl und Dichte von Lichtobjekten enthalten, die Schatten werfen (oder eine hohe Anzahl und Dichte kleiner Teile, die von Schatten beeinflusst werden), sind wahrscheinlich mit Leistungsproblemen verbunden.
Hohe Transparenzüberschreitung - Das Platzieren von Objekten mit partieller Transparenz in der Nähe einander zwingt die Engine, die überlappenden Pixel mehrmals zu rendern, was die Leistung schädigen kann.Für weitere Informationen zur Identifizierung und Behebung dieses Problems sehen Sie Layerierte Transparenzen löschen.
Abmildigung
- Instanzierung identischer Meshes und Reduzierung der Menge einzigartiger Meshes - Wenn Sie sicherstellen, dass alle identischen Meshes die gleichen Unternehmens-IDs haben, kann die Engine sie erkennen und in einer einzigen Draw-Aufruf rendern.Stellen Sie sicher, dass Sie jedes Netz nur einmal in einer Karte hochladen und es dann in Studio duplizieren, um es wiederzuverwenden, anstatt große Karten als Ganzes zu importieren, was dazu führen kann, dass identische Netze separate Inhalts-IDs haben und vom Motor als einzigartige Assets erkannt werden.Pakete sind ein hilfreicher Mechanismus zur Wiederverwendung von Objekten.
- Auslese - Auslese beschreibt den Prozess der Eliminierung von Ziehaufrufen für Objekte, die sich nicht in den endgültigen gerenderten Rahmen einfügenStandardmäßig überspringt die Engine Ziehaufrufe für Objekte außerhalb des Sichtfelds der Kamera (Frustum-Auslese), aber nicht Ziehaufrufe für Objekte, die durch andere Objekte aus der Sicht ausgeschlossen sind (Ausschluss-Auslese).Wenn deine Szene eine große Anzahl von Ziehaufrufen hat, erwäge, deine eigene zusätzliche Auswahl zur Laufzeit dynamisch für jeden Frame umzusetzen, z. B. die Anwendung der folgenden häufigen Strategien:
- Für Innenumgebungen implementieren Sie ein Zimmer- oder Portal-System, das Objekte versteckt, die derzeit von keinen Benutzern besetzt sind.
- Reduzierung der Rendertreue - Stellen Sie die Rendertreue auf Automatisch oder Leistung fest.Dies ermöglicht Meshes, zu weniger komplexen Alternativen zurückzufallen, was die Anzahl der zu zeichnenden Polygone reduzieren kann.
- Deaktivierung von Schattenwurf auf geeignete Teile und Lichtobjekte - Die Komplexität der Schatten in einer Szene kann durch die selektive Deaktivierung von Schattenwurf-Eigenschaften auf Lichtobjekten und Teile reduziert werden.Dies kann zur Bearbeitungszeit oder dynamisch zur Laufzeit erfolgen.Einige Beispiele sind:
Verwende die BasePart.CastShadow-Eigenschaft, um Schattenwurf auf kleinen Teilen zu deaktivieren, auf denen es unwahrscheinlich ist, dass Schatten sichtbar sind.Dies kann besonders effektiv sein, wenn es nur auf Teile angewendet wird, die weit von der Kamera des Benutzers entfernt sind.
Deaktiviere Schatten bei bewegenden Objekten, wenn es möglich ist
Deaktivieren Sie Light.Shadows auf leichten Instanzen, wo das Objekt keine Schatten werfen muss.
Begrenzen Sie die Reichweite und den Winkel der Lichtinstanzen.
Verwenden Sie weniger leichte Instanzen.
Mikroprofilierungs-Scopes
Umfang | Verknüpfte Berechnung |
Vorbereiten und durchführen | Gesamtes Rendern |
Ausführen/Szene/computeLightingPerform | Lichtgitter- und Schattenaktualisierungen |
Leichte Gitter-CPU | Aktualisierungen des Voxel-Lichtgitters |
Schattenkartensystem | Schattenmapping |
Ausführen/Szene/UpdateView | Vorbereitung für Rendering und Partikel-Updates |
Ausführen/Szene/Renderansicht | Renderung und Nachbearbeitung |
Netzwerk und Replikation
Netzwerk- und Replikationsbeschreibung beschreibt den Prozess, bei dem Daten zwischen dem Server und den verbundenen Clients gesendet werden.Informationen werden zwischen dem Client und dem Server jedes Frame gesendet, aber größere Mengen an Informationen erfordern mehr Berechnungszeit
Häufige Probleme
Übertriebener Fernverkehr - Das Senden einer großen Menge an Daten durch RemoteEvent oder RemoteFunction Objekte oder das häufige Aufrufen von ihnen kann dazu führen, dass eine große Menge an CPU-Zeit für die Verarbeitung eingehender Pakete pro Frame ausgegeben wird.Gewöhnliche Fehler umfassen:
- Daten replizieren, jeden Frame, der nicht repliziert werden muss.
- Daten replizieren auf Benutzereingabe ohne irgendeinen Mechanismus, um sie zu drosseln.
- Versenden von mehr Daten als erforderlich.Zum Beispiel, das gesamte Inventar des Spielers zu senden, wenn sie ein Artikel kaufen, anstatt nur Details des gekauften Artikels.
Erstellung oder Entfernung komplexer Instanzbäume - Wenn eine Änderung am Datenmodell auf dem Server vorgenommen wird, wird sie auf verbundene Clients repliziert.Das bedeutet, die Erstellung und Zerstörung großer Instanz-Hierarchien wie Karten zur Laufzeit kann sehr netzwerkintensiv sein.
Ein häufiger Schuldiger hier sind die komplexen Animationsdaten, die von Animations-Editor-Plugins in Rigs gespeichert werden.Wenn diese nicht vor der Veröffentlichung des Spiels entfernt werden und das animierte Modell regelmäßig geklont wird, wird eine große Menge an Daten unnötig repliziert.
Server-seitiger TweenService - Wenn TweenService verwendet wird, um einen Objektserver seitlich zu durchschalten, wird die durchgeschaltete Eigenschaft in jedem Frame auf jeden Client repliziert.Dies führt nicht nur dazu, dass der Teenager nervös wird, wenn sich die Latenz der Clients verändert, sondern verursacht auch viel unnötigen Netzwerkverkehr.
Abmildigung
Sie können die folgenden Taktiken einsetzen, um unnötige Replikation zu reduzieren:
- Vermeiden Sie das Senden großer Mengen an Daten auf einmal durch Remote-Ereignisse .Senden Sie stattdessen nur notwendige Daten mit einer niedrigeren Frequenz.Zum Beispiel für den Zustand eines Charakters, reproduziere ihn, wenn er sich ändert, anstatt jedes Frame.
- Füge komplexe Instanzbaumstrukturen zusammen wie Karten und lade sie in Stücke auf, um die Arbeit zu verteilen, die diese über mehrere Frames repliziert.
- Löschen von Animationsmetadaten , insbesondere der Animationsdirektory von Rigs, nach dem Importieren.
- Beschränken Sie die unnötige Instanzreplikation , insbesondere in Fällen, in denen der Server nicht wissen muss, dass die erstellten Instanzen existierenDies beinhaltet:
- Visuelle Effekte wie eine Explosion oder eine magische Zauberexplosion.Der Server muss nur die Lokalität kennen, um das Ergebnis zu bestimmen, während die Clients visuelle Inhalte lokal erstellen können.
- First-Person-Artikelansichtsmodelle.
- Zwischenobjekte auf dem Client anstatt auf dem Server.
Mikroprofilierungs-Scopes
Umfang | Verknüpfte Berechnung |
Prozesspakete | Verarbeitung von eingehenden Netzwerkpaketen, wie Ereignisaufrufen und Eigenschaftsänderungen |
Bandbreite zuweisen und Sender ausführen | Ausgehende Ereignisse relevant auf Servern |
Asset-Speicherverwendung
Der höchste Auswirkungsmechanismus, den Ersteller zur Verbesserung der Client-Speicherverwendung zur Verfügung haben, besteht darin, Instanzstreaming zu aktivieren.
Instanz-Streaming
Instance-Streaming lässt Teile des Datenmodells selektiv laden, die nicht benötigt werden, was zu einer deutlich reduzierten Ladezeit führt und die Fähigkeit des Clients erhöht, Kollisionen zu verhindern, wenn er unter Druck kommt.
Wenn Sie Speicherprobleme auftreten und Instanzstreaming deaktiviert ist, erwägen Sie, Ihr Erlebnis zu aktualisieren, um es zu unterstützen, insbesondere wenn Ihre 3D-Welt groß ist.Instance-Streaming basiert auf der Entfernung im 3D-Raum, sodass größere Welten natürlich mehr davon profitieren.
Wenn das Instanzstreaming aktiviert ist, kannst du die Aggressivität erhöhen. Zum Beispiel:
- Reduzierung der Verwendung der persistenten StreamingIntegrity .
- Reduzierung des Streamingradius .
Für weitere Informationen zu Streaming-Optionen und ihren Vorteilen, siehe Streaming-Eigenschaften.
Andere häufige Probleme
- Asset-Duplikation - Ein häufiger Fehler besteht darin, dasselbe Asset mehrmals hochgeladen wird, was zu unterschiedlichen Asset-IDs führt.Dies kann dazu führen, dass derselbe Inhalt mehrmals in den Speicher geladen wird.
- Übertriebene Asset-Volumen - Selbst wenn die Assets nicht identisch sind, gibt es Fälle, in denen Gelegenheiten verpasst werden, dasselbe Asset wiederzuverwenden und Speicher zu sparen.
- Audiodateien - Audiodateien können ein überraschender Beitrag zur Speicherverwendung sein, insbesondere, wenn Sie sie alle auf einmal in den Client laden, anstatt nur das zu laden, was Sie für einen Teil der Erfahrung benötigen.Für Strategien siehe Ladezeiten.
- Hochauflösende Texturen - Der Grafikspeicherverbrauch für eine Textur ist unabhängig von der Größe der Textur auf der Festplatte, sondern vielmehr von der Anzahl der Pixel in der Textur
- Zum Beispiel verbraucht eine 1024x1024-Pixeltextur viermal die Grafikspeicher einer 512x512-Texture.
- Bilder, die auf Roblox hochgeladen werden, werden in ein festes Format transcodiert, so dass es keinen Speichervorteil gibt, Bilder in einem Farbmodell mit weniger Bytes pro Pixel hochzuladen.Ebenso kann das Komprimieren von Bildern vor dem Hochladen oder das Entfernen des Alphakanals von Bildern, die es nicht benötigen, die Bildgröße auf der Festplatte verringern, aber entweder verbessert es sich nicht oder verbessert es nur minimal die Speicherverwendung.Obwohl die Engine die Texturauflösung auf einigen Geräten automatisch herunterskaliert, hängt das Ausmaß der Herunterskalierung von den Gerätemerkmalen ab, und eine übermäßige Texturauflösung kann immer noch Probleme verursachen.
- Du kannst die Grafikspeicherverbrauch für eine bestimmte Textur identifizieren, indem du die Grafiktextur -Kategorie in der Entwicklerkonsole erweiterst.
Abmildigung
- Lade nur einmal Assets hoch - Wiederverwende die gleiche Asset-ID über Objekte und stelle sicher, dass die gleichen Assets, insbesondere Meshes und Bilder, nicht mehrfach separat hochgeladen werden.
- Finde und korrigiere doppelte Assets - Suche nach identischen Mesh-Teilen und Texturen, die mit verschiedenen IDs mehrfach hochgeladen werden.
- Obwohl es keine API gibt, die Ähnlichkeiten von Assets automatisch erkennt, kannst du alle Bild-Asset-IDs in deinem Platz sammeln (manuell oder mit einem Skript), herunterladen und vergleichen, indem du externe Vergleichswerkzeuge verwendest.
- Für Mesh-Teile ist die beste Strategie, einzigartige Mesh-IDs zu nehmen und sie nach Größe zu organisieren, um Duplikate manuell zu identifizieren.
- Anstatt separate Texturen für verschiedene Farben zu verwenden, lade eine einzige Textur hoch und verwende die Eigenschaft SurfaceAppearance.Color, um verschiedene Tönungen darauf anzuwenden.
- Assets in der Karte separat importieren - Statt eine gesamte Karte auf einmal zu importieren, importiere und konstruiere Assets in der Karte einzeln und konstruiere sie neu.Der 3D-Importierer führt keine De-Duplikation von Meshes durch, also wenn du eine große Karte mit vielen separaten Bodenplatten importieren würdest, würde jede dieser Platten als separates Asset importiert werden (auch wenn sie dupliziert sind).Dies kann zu Leistungs- und Speicherproblemen auf der Linie führen, da jedes Mesh als einzeln behandelt wird und Speicher und Anrufe aufnimmt.
- Beschränken Sie die Pixel von Bildern auf nicht mehr als die notwendige MengeEs sei denn, ein Bild belegt eine große Menge an physischem Raum auf dem Bildschirm, es benötigt in der Regel höchstens 512x512 Pixel.Die meisten kleineren Bilder sollten kleiner als 256x256 Pixel sein.
- Verwende Trim-Blätter , um maximale Texturwiederverwendung in 3D-Karten zu gewährleisten.Für Schritte und Beispiele, wie man Trim-Blätter erstellt, siehe Trim-Blätter erstellen.
Ladezeiten
Viele Erlebnisse implementieren benutzerdefinierte Ladebildschirme und verwenden die ContentProvider:PreloadAsync()-Methode, um Assets anzufordern, so dass Bilder, Sounds und Meshes im Hintergrund heruntergeladen werden.
Der Vorteil dieser Herangehensweise besteht darin, dass Sie sicherstellen können, dass wichtige Teile Ihrer Erfahrung ohne Pop-in vollständig geladen werden.Allerdings ist ein häufiger Fehler die übermäßige Nutzung dieser Methode, um mehr Assets vorzuladen, als tatsächlich erforderlich sind.
Ein Beispiel für eine schlechte Praxis ist das Laden der gesamtenWorkspace .Während dies die Textur-Pop-Ins verhindern kann, erhöht es die Ladezeit erheblich.
Stattdessen verwenden Sie nur ContentProvider:PreloadAsync() in notwendigen Situationen, die umfassen:
- Bilder im Ladebildschirm.
- Wichtige Bilder in deinem Erlebnismenü, wie zum Beispiel Knopf-Hintergründe und -Ikonen.
- Wichtige Assets im Start- oder Spawn-Bereich.
Wenn Sie eine große Anzahl von Assets laden müssen, empfehlen wir Ihnen, eine Laden überspringen Schaltfläche bereitzustellen.