Ta strona opisuje powszechne problemy z wydajnością i najlepsze praktyki w ich łagodzeniu.
Obliczanie skryptów
Kosztowne operacje w kodzie Luau zajmują dłużej na przetworzenie i mogą zatem wpłynąć na szybkość ramki.Chyba że jest wykonywany równolegle, kod Luau jest wykonywany równocześnie i blokuje główny wątek, dopóki nie spotka funkcję, która zwraca wątek.
Wspólne problemy
Intensywne operacje na strukturach tabeli - Skomplikowane operacje, takie jak serjalizacja, odserializacja i głębokie klonowanie, generują wysokie koszty wydajności, szczególnie na dużych strukturach tabeli.Jest to szczególnie prawda, jeśli te operacje są rekurencyjne lub obejmują iterowanie nad bardzo dużymi strukturami danych.
Wydarzenia o wysokiej częstotliwości - Łączenie drogich operacji z wydarzeniami opartymi na ramach RunService oznacza, że operacje te powtarzają się za każdym razem, co często prowadzi do niepotrzebnego zwiększenia czasu obliczeń.Wydarzenia te obejmują:
Złagodzenie
- Wzywaj kod na wydarzeniach RunService oszczędnie, ograniczając jego użycie do przypadków, w których wysoka częstotliwość wezwania jest niezbędna (na przykład aktualizacja kamery).Możesz wykonać większość innego kodu w innych wydarzeniach lub rzadziej w pętlu.
- Rozbijaj duże lub kosztowne zadania za pomocą task.wait() rozprzestrzeniając pracę na wiele ram.
- Zidentyfikuj i zoptymalizuj niepotrzebnie drogie operacje i użyj wielowątkowości do kosztownych operacji obliczeniowych, które nie muszą mieć dostępu do modelu danych.
- Niektóre skrypty stronowe mogą skorzystać z natywnej generacji kodu, prostego flaga, która kompiluje skrypt do kodu maszynowego, a nie kodu bajtów.
Zakresy mikroprofilera
Zakres | Powiązane obliczenia |
Wykonaj usługę.PreRender | Kod wykonujący na wydarzeniu PreRender |
Wykonaj usługę.PreSimulation | Kod wykonujący na wydarzeniu Stepped |
Wykonaj usługę.PostSimulation | Kod wykonujący na wydarzeniu Heartbeat |
Heartbeat usługi RunService | Kod wykonujący na wydarzeniu Heartbeat |
Aby uzyskać więcej informacji o debugowaniu skryptów za pomocą mikroprofilera, zobacz bibliotekę debug, która zawiera funkcje do oznaczania konkretnego kodu i dalszego zwiększania specyfiki, takie jak debug.profilebegin i debug.profileend.Wiele metod API Roblox wezwanych przez skrypty ma również własne powiązane tagi mikroprofilera, które mogą dostarczyć użyteczny sygnał.
Użycie pamięci skryptu
Wycieki pamięci mogą wystąpić, gdy piszesz skrypty, które zużywają pamięć, której zbieracz śmieci nie może właściwie uwolnić, gdy nie jest już używany.Wycieki są specjalnie powszechne na serwerze, ponieważ mogą być ciągle online przez wiele dni, podczas gdy sesja klienta jest znacznie krótsza.
Wartości pamięci następujące w Konsoli programisty mogą wskazać problem, który wymaga dalszych badań:
- LuaHeap - Wysoka lub rosnąca konsumpcja sugeruje wyciek pamięci.
- Liczba instancji - Konsekwentnie rosnąca liczba instancji sugeruje, że odniesienia do niektórych instancji w twoim kodzie nie są gromadzone w pamięci.
- Pamięć skryptu miejscowego - Dostarcza skrypt przez podział pamięci na użycie skryptu.
Wspólne problemy
Pozostawianie połączeń włączonych - Silnik nigdy nie gromadzi odpadów wydarzeń połączonych z instancją i żadnych wartości odwołanych wewnątrz połączonego powrotu.Dlatego aktywne połączenia wydarzeń i kodu wewnątrz połączonych instancji, połączonych funkcji i odwołanych wartości są poza zakresem dla zbieracza pamięci odpadów, nawet po wystrzeleniu wydarzeń.
Chociaż wydarzenia są odłączone, gdy instancja, do której należą, zostanie usunięta, powszechnym błędem jest założenie, że dotyczy to obiektów Player.Po opuszczeniu doświadczenia przez użytkownika silnik nie automatycznie niszczy jego reprezentatywnego obiektu Player i modelu postaci, więc połączenia do obiektu Player i instancji w ramach modelu postaci, takich jak Player.CharacterAdded, nadal zużywają pamięć, jeśli nie odłączysz ich w swoich skryptach.Może to doprowadzić do bardzo znacznych wycieków pamięci z biegiem czasu na serwerze, gdy setki użytkowników dołącza i opuszcza doświadczenie.
Tabele - Wstawianie obiektów do tabel, ale nie usuwanie ich, gdy nie są już potrzebne, powoduje niepotrzebne zużycie pamięci, szczególnie dla tabel, które śledzą dane użytkownika, gdy dołączają.Na przykład następujący przykład kodu tworzy tabelę, która dodaje informacje o użytkowniku za każdym razem, gdy użytkownik dołącza:
Przykładlocal playerInfo = {}Players.PlayerAdded:Connect(function(player)playerInfo[player] = {} -- nieco informacjiend)Jeśli nie usuniesz tych wpisów, gdy nie są już potrzebne, tabela nadal rośnie w rozmiarze i zużywa więcej pamięci, gdy do sesji dołącza więcej użytkowników.Każdy kod, który iteruje nad tą tabelą, staje się również bardziej kosztowny pod względem obliczeń, gdy tabela rośnie w rozmiarze.
Złagodzenie
Aby wyczyścić wszystkie używane wartości, aby zapobiec wyciekom pamięci:
Rozłącz wszystkie połączenia - Przejdź przez bazę kodu, aby upewnić się, że każde połączenie zostało wyczyszczone za pomocą jednej z następujących ścieżek:
- Rozłączanie ręcznie za pomocą funkcji Disconnect().
- Niszczenie instancji, do której należy wydarzenie za pomocą funkcji Destroy().
- Niszczenie obiektu skryptu, do którego odwołuje się połączenie
Usuń obiekty i postacie gracza po opuszczeniu - Wdroż kod, aby zapewnić, że po opuszczeniu przez użytkownika nie utrzymują się połączenia, tak jak w następnym przykładzie:
PrzykładPlayers.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)
Obliczenia fizyczne
Nadmierna symulacja fizyczna może być główną przyczyną zwiększonego czasu obliczeń na ramę na serwerze i klientzie.
Wspólne problemy
Nadmierna częstotliwość kroków fizycznych - Domyślnie zachowanie kroków jest w trybie adaptacyjnym, gdzie kroki fizyczne w 60 Hz, 120 Hz lub 240 Hz, w zależności od złożoności mechanizmu fizycznego.
Dostępny jest również tryb stały z poprawioną dokładnością fizyki, który zmusza wszystkie zespoły fizyczne do skoku z częstotliwością 240 Hz (cztery razy na ramę).Wynika to z znacznie większej liczby obliczeń każdej ramy.
Nadmierna liczba złożoności symulowanych obiektów - Im więcej 3D zespołów, które są symulowane, tym dłużej trwają obliczenia fizyczne w każdym ramie.Często doświadczenia będą miały obiekty, które są symulowane, które nie muszą być lub będą miały mechanizmy, które mają więcej ograniczeń i stawów niż potrzebują.
Nadmiernie precyzyjne wykrywanie kolizji - części siatki mają właściwość CollisionFidelity wykrywania kolizji, która oferuje różne modele o różnym poziomie wpływu na wydajność.Dokładny tryb wykrywania kolizji dla części siatkowych ma najwyższy koszt wydajności i wymaga dłuższego czasu na obliczenie silnika.
Złagodzenie
Kotwiczne części, które nie wymagają symulacji - Kotwicz wszystkie części, które nie muszą być napędzane przez fizykę, takie jak dla statycznych NPC.
Użyj adaptacyjnego krokowania fizyki - adaptacyjne krokowanie dynamicznie dostosowuje szybkość obliczeń fizyki dla mechanizmów fizycznych, umożliwiając dokonywanie aktualizacji fizyki rzadziej w niektórych przypadkach.
Zmniejsz złożoność mechanizmu * W miarę możliwości zmniejsz liczbę ograniczeń fizycznych lub połączeń w złożeniu.
- Zmniejsz ilość samokolizji w mechanizmie, taką jak nałożenie ograniczeń lub zakazów kolizji na kończyny ragdoll, aby zapobiec ich zderzaniu się ze sobą.
Zmniejsz użycie precyzyjnej wierności kolizji dla siatek * Dla małych lub niedziałających obiektów, w których użytkownicy rzadko zauważą różnicę, użyj wierności pudełka.
Dla obiektów o małej lub średniej wielkości użyj wierności pudełka lub kadłuba, w zależności od kształtu.
Dla dużych i bardzo złożonych obiektów buduj niestandardowe kolizje za pomocą niewidzialnych części, jeśli to możliwe.
Dla obiektów, które nie wymagają kolizji, wyłącz kolizje i użyj wierności pudełka lub kadłuba, ponieważ geometria kolizji jest nadal przechowywana w pamięci.
Możesz wyrenderować geometrię kolizji do celów debugowania w Studio, przełączając wierność kolizji z widgetu opcje wizualizacji w prawym górnym rogu widoku 3D.
Alternatywnie możesz zastosować filtr CollisionFidelity=PreciseConvexDecomposition do Eksploratora, który pokazuje liczbę wszystkich części siatki z dokładną wiernością i pozwala łatwo je wybrać.
Aby uzyskać szczegółowy przegląd sposobu wyboru opcji wierności kolizji, która zrównoważa twoje wymagania precyzji i wydajności, zobacz Ustaw parametry fizyki i renderowania.
Zakresy mikroprofilera
Zakres | Powiązane obliczenia |
fizyka krok po kroku | Ogólne obliczenia fizyki |
krok świata | Dyskretne kroki fizyki wykonywane co każdą ramę |
Użycie pamięci fizycznej
Ruch fizyczny i wykrywanie kolizji zużywają pamięć.Części siatki mają właściwość CollisionFidelity, która określa podejście używane do oceny granic kolizji siatki.
Wspólny problem
Domyślny i precyzyjny tryb wykrywania kolizji zużywa znacznie więcej pamięci niż dwa pozostałe tryby z niższą jakością kolizji.
Jeśli widzisz wysokie poziomy zużycia pamięci pod częściami fizycznymi , możesz potrzebować zbadania zmniejszenia wierności kolizji obiektów w swoim doświadczeniu.
Jak złagodzić
Aby zmniejszyć wykorzystywaną pamięć dla wierności kolizji:
- Dla części, które nie wymagają kolizji, wyłącz ich kolizje poprzez ustawienie BasePart.CanCollide, BasePart.CanTouch i BasePart.CanQuery na false.
- Zmniejsz wierność kolizji za pomocą ustawienia CollisionFidelity.Box ma najniższe obciążenie pamięci, a Default i Precise są ogólnie droższe.
- Zasadniczo bezpieczne jest ustawienie wierności kolizji dowolnej małej osadzonej części na Box .
- W przypadku bardzo złożonych dużych siatek możesz chcieć zbudować własną siatkę kolizyjną z mniejszymi obiektami z wiernością kolizji pudełka.
Humanoidy
Humanoid jest klasą, która zapewnia szeroką gamę funkcjonalności dla postaci gracza i niegracza (NPC).Chociaż potężny, Humanoid przychodzi z znaczącym kosztem obliczeń.
Wspólne problemy
- Pozostawienie wszystkich HumanoidStateTypes włączonych na NPCach - Istnieje koszt wydajności z pozostawieniem pewnych HumanoidStateTypes włączonych.Wyłącz wszystkie, które nie są potrzebne do twoich NPCów.Na przykład, chyba że twój NPC zamierza wspiąć się na drabiny, bezpiecznie jest wyłączyć stan Climbing.
- Instancjalizowanie, modyfikowanie i odrodzenie modeli z ludźmi często * Może to być intensywne dla silnika do przetwarzania, szczególnie jeśli te modele używają wielowarstwowej odzieży .Może to być szczególnie problematyczne w doświadczeniach, w których awatary często odrodzić.
- W Mikroprofilu , długie tagi aktualizacjaNieważne klastry szybkie (ponad 4 ms) są często sygnałem, że instancjalizacja/modyfikacja awatara wywołuje nadmierne nieważności.
- Korzystanie z humanoidów w przypadkach, gdy nie są one wymagane - Statyczne NPC, które nie poruszają się ogólnie, nie mają potrzeby klasy Humanoid.
- Granie animacji na dużej liczbie NPC z serwera - animacje NPC, które uruchamiają się na serwerze, muszą być symulowane na serwerze i replikowane do klienta.Może to być zbędne obciążenie.
Złagodzenie
- Odtwarzaj animacje NPC na klientzie - W przypadkach z dużą liczbą NPCów rozważ stworzenie Animator na klientzie i wykonanie animacji lokalnie.Zmniejsza to obciążenie na serwerze i potrzebę niepotrzebnej replikacji.Umożliwia także dodatkowe optymalizacje (na przykład tylko odtwarzanie animacji dla NPCów, które są blisko postaci).
- Wykorzystaj przyjazne dla wydajności alternatywy dla Humanoidów - modele NPC niekoniecznie muszą zawierać obiekt humanoidowy.
- Dla statycznych NPCów użyj prostej AnimationController, ponieważ nie muszą się poruszać, ale po prostu potrzebują odtwarzać animacje.
- Dla przesuwania NPCów rozważ implementację własnego kontrolera ruchu i użycie AnimationController dla animacji, w zależności od złożoności Twoich NPCów.
- Wyłącz niewykorzystane stany humanoidów - Użyj Humanoid:SetStateEnabled(), aby włączyć tylko niezbędne stany dla każdego humanoida.
- Modele NPC z częstym odrodzeniem - Zamiast niszczyć NPC całkowicie, wyślij NPC do basenu nieaktywnych NPC.W ten sposób, gdy wymagane jest odrodzenie nowego NPC, możesz po prostu ponownie aktywować jednego z NPC z basenu.Proces ten nazywa się poolowaniem, co minimalizuje liczbę razy, w których konieczne jest instancjowanie znaków.
- Spawnuj tylko NPC, gdy użytkownicy są w pobliżu - Nie spawnuj NPC, gdy użytkownicy nie są w zasięgu, i wyeliminuj ich, gdy użytkownicy opuszczą swój zasięg.
- Unikaj dokonywania zmian w hierarchii awatara po jej instancjalizacji - Niektóre modyfikacje hierarchii awatara mają znaczące implikacje dla wydajności.Dostępne są niektóre optymalizacje:
- W przypadku niestandardowych animacji proceduralnych nie aktualizuj właściwości JointInstance.C0 i JointInstance.C1. Zamiast tego aktualizuj właściwość Motor6D.Transform.
- Jeśli musisz przymocować jakiekolwiek BasePart obiekty do awatara, zrób to poza hierarchią awatara Model.
Zakresy mikroprofilera
Zakres | Powiązane obliczenia |
stepsHumanoidowy | Kontrola i fizyka humanoidów |
stopniowa animacja | Animacja ludzkiego i animatora |
aktualizacja Nieaktualizowane szybkie klastry | Związane z instancjalizacją lub modyfikacją awatara |
Renderowanie
Znaczna część czasu, jaki klient spędza na każdym ramie, jest poświęcona na renderowanie sceny w obecnym ramie.Serwer nie wykonuje żadnego renderowania, więc ta sekcja jest wyłączna dla klienta.
Wywołaj wezwania
Wezwanie do rysowania to zbiór instrukcji od silnika do GPU do renderowania czegoś.Wezwania do rysowania mają znaczny nadmiar.Ogólnie rzecz biorąc, im mniej jest wezwań do rysowania na ramę, tym mniej czasu obliczeniowego jest poświęcane na renderowanie ramy.
Możesz zobaczyć, ile wezwań do renderowania występuje obecnie z przedmiotem Statystyki renderowania > Czas w Studio.Możesz wyświetlić Statystyki renderowania w klientzie, naciskając ShiftF2.
Im więcej obiektów musi być narysowanych w twojej scenie w danym ramie, tym więcej wezwań do GPU jest wykonywanych.Jednak silnik Roblox wykorzystuje proces o nazwie instancjonowanie, aby skompresować identyczne siatki z tymi samymi cechami tekstury do pojedynczego wezwania rysowania.W szczególności wiele siatek z tymi samymi MeshId jest obsługiwanych w jednym wezwaniu do rysowania, gdy:
- Materiały są identyczne, gdy oba SurfaceAppearance i MeshPart.TextureID nie istnieją.
Inne powszechne problemy
Nadmierna gęstość obiektów - Jeśli duża liczba obiektów jest skoncentrowana z dużą gęstością, renderowanie tej części sceny wymaga więcej wezwań do rysowania.Jeśli masz problem z szybkością ramienia, gdy patrzysz na pewną część mapy, może to być dobry sygnał, że gęstość obiektów w tym obszarze jest zbyt wysoka.
Obiekty takie jak znaki, tekstury i cząsteczki nie są dobrze rozdzielane i wprowadzają dodatkowe wezwania do rysowania.Zwróć szczególną uwagę na te typy obiektów w scenie.W szczególności zmiany właściwości do ParticleEmitters mogą mieć dramatyczny wpływ na wydajność.
Brak możliwości instancjonowania pominiętych - Często scenka będzie zawierać tę samą siatkę powtórzoną wiele razy, ale każda kopia siatki ma różne ID zasobów siatki lub tekstury.Uniemożliwia to instancjonowanie i może prowadzić do niepotrzebnych wezwań do rysowania.
Wspólną przyczyną tego problemu jest sytuacja, gdy cała scena jest importowana naraz, zamiast importować poszczególne zasoby do Roblox, a następnie powielić je po ich zaimportowaniu, aby złożyć scenę.
Nawet prosty skrypt taki jak ten może pomóc ci zidentyfikować części siatki o tej samej nazwie, które używają różnych identyfikatorów siatki:
local Workspace = game:GetService("Workspace")for _, descendant in Workspace:GetDescendants() doif descendant:IsA("MeshPart") thenprint(descendant.Name .. ", " .. descendant.MeshId)endendWyjście (z włączonym Liniami stosu ) może wyglądać tak.Powtarzające się linie wskazują na ponowne wykorzystanie tego samego siatki, co jest dobre.Unikalne linie niekoniecznie są złe, ale w zależności od twojego systemu nazywania może wskazywać na powielone siatki w twoim doświadczeniu:
LargeRock, rbxassetid://106420009602747 (x144) -- goodLargeRock, rbxassetid://120109824668127LargeRock, rbxassetid://134460273008628LargeRock, rbxassetid://139288987285823LargeRock, rbxassetid://71302144984955LargeRock, rbxassetid://90621205713698LargeRock, rbxassetid://113160939160788LargeRock, rbxassetid://135944592365226 -- all possible duplicatesNadmierna złożoność obiektu - Chociaż nie jest tak ważna jak liczba wezwań do rysowania, liczba trójkątów w scenie wpływa na to, jak długo potrwa renderowanie ramki.Sceny z bardzo dużą liczbą bardzo skomplikowanych siatek są powszechnym problemem, podobnie jak sceny z właściwością MeshPart.RenderFidelity ustawioną na Enum.RenderFidelity.Precise na zbyt wielu siatkach.
Nadmierne rzucanie cieni - Przetwarzanie cieni jest kosztowne, a mapy zawierające dużą liczbę i gęstość światła rzucające cienie (lub dużą liczbę i gęstość małych części wpływanych przez cienie) prawdopodobnie będą miały problemy z wydajnością.
Wysoka przejrzystość przeciągnięcia - Umieszczenie obiektów o częściowej przejrzystości w pobliżu siebie zmusza silnik do renderowania pokrywających się pikli wielokrotnie, co może zaszkodzić wydajności.Aby uzyskać więcej informacji na temat identyfikacji i naprawy tego problemu, zobacz Usuń przeźroczystości warstwowe.
Złagodzenie
- Instancjonowanie identycznych siatek i zmniejszanie ilości unikalnych siatek - Jeśli zapewnisz, że wszystkie identyczne siatki mają te same ID zasobów podstawowych, silnik może je rozpoznać i renderować w jednym połączeniu wywołania.Upewnij się, że każdą siatkę przesyłasz tylko raz na mapie, a następnie powielasz je w Studio, aby je ponownie wykorzystać, zamiast importować duże mapy jako całość, co może spowodować, że identyczne siatki będą miały odrębne ID zawartości i zostaną rozpoznane jako unikalne zasoby przez silnik.Pakiety są pomocnym mechanizmem do ponownego wykorzystania obiektów.
- Oczyszczanie - Oczyszczanie opisuje proces usuwania wezwań do obiektów, które nie wchodzą w skład ostatecznego renderowanego obrazu.Domyślnie silnik pomija wezwania do rysowania dla obiektów poza polem widzenia kamery (wycinka frustum), ale nie pomija wezwań do rysowania dla obiektów ukrytych z widoku przez inne obiekty (wycinka ukrycia).Jeśli twoja scena ma dużą liczbę wezwań do rysowania, rozważ wdrożenie własnego dodatkowego przesiewania dynamicznie na czasie dla każdej ramy, takie jak zastosowanie następujących wspólnych strategii:
- W przypadku środowisk wewnętrznych wdroż system pokoju lub portalu, który ukrywa obiekty nie zajęte obecnie przez żadnych użytkowników.
- Zmniejszanie wierności renderowania - Ustaw wierność renderowania na Automatyczną lub Wydajność .Umożliwia to powrotowi siatek do mniej skomplikowanych alternatyw, które mogą zmniejszyć liczbę poligonów, które należy narysować.
- Wyłączanie rzucania cieni na odpowiednich częściach i lekkich obiektach - Złożoność cieni w scenie można zmniejszyć poprzez wyłączanie właściwości rzucania cieni na lekkich obiektach i częściach selektywnie.Można to zrobić w czasie edycji lub dynamicznie podczas uruchamiania.Niektóre przykłady to:
Użyj właściwości BasePart.CastShadow, aby wyłączyć rzucanie cieni na małych częściach, na których prawdopodobnie nie będą widoczne cienie.Może to być szczególnie skuteczne, gdy zostanie zastosowane tylko do części oddalonych od kamery użytkownika.
Wyłącz cienie na poruszających się obiektach, jeśli to możliwe.
Wyłącz Light.Shadows na lekkich instancjach, gdzie obiekt nie musi rzucać cieni.
Ogranicz zasięg i kąt światła instancji.
Użyj mniej instancji światła.
Rozważ wyłączenie świateł, które są poza określonym zakresem lub na podstawie pokoju do pokoju dla środowisk wewnętrznych.
Zakresy mikroprofilera
Zakres | Powiązane obliczenia |
Przygotuj i wykonaj | Ogólne renderowanie |
Wykonaj/Scenę/ computeLightingPerform | Aktualizacje siatki światła i cienia |
ŚwiatłoGridCPU | Aktualizacje siatki światła wokselowego |
System mapy cienia | Mapowanie cieni |
Wykonaj/Scenę/Zaktualizuj widok | Przygotowanie do renderowania i aktualizacji cząstek |
Wykonaj/Scena/RenderView | Renderowanie i post-przetwarzanie |
Sieciowanie i replikacja
Sieciowanie i replikacja opisuje proces, w którym dane są wysyłane między serwerem a połączonymi klientami.Informacje są wysyłane między klientem a serwerem co każdą ramę, ale większe ilości informacji wymagają więcej czasu obliczeń.
Wspólne problemy
Nadmierny ruch zdalny - Wysyłanie dużej ilości danych za pośrednictwem lub obiektów lub wzywanie ich bardzo często może doprowadzić do dużej ilości czasu CPU poświęcanego na przetwarzanie otrzymanych pakietów w każdym ramie.Powszechne błędy obejmują:
- Replikowanie danych każdego ramu, który nie musi być replikowany.
- Replikowanie danych na wejściu użytkownika bez mechanizmu ograniczania ich.
- Wysyłanie większej ilości danych niż jest wymagane.Na przykład wysyłanie całego zapasu gracza, gdy kupują przedmiot, a nie tylko szczegóły zakupionego przedmiotu.
Tworzenie lub usuwanie złożonych drzew instancji - Kiedy dokonana zostanie zmiana w modelu danych na serwerze, zostanie ona odzwierciedlona w połączonych klientach.Oznacza to, że tworzenie i niszczenie dużych hierarchii instancji, takich jak mapy, podczas uruchamiania może być bardzo intensywne w sieci.
Wspólnym winowajcą jest tutaj złożone dane animacji zapisane przez wtyczki edytora animacji w rygach.Jeśli nie zostaną one usunięte przed opublikowaniem gry i animowany model będzie regularnie kopiowany, duża ilość danych zostanie powielona niepotrzebnie.
Serwis tweeningu strony serwera - Jeśli TweenService jest używany do tweenowania obiektu po stronie serwera, właściwość tweenowana jest replikowana do każdego klienta co każdą ramę.Nie tylko powoduje to, że nastolatek jest zdenerwowany, gdy zmienia się opóźnienie klientów, ale powoduje również wiele niepotrzebnego ruchu sieciowego.
Złagodzenie
Możesz stosować następujące taktyki, aby zmniejszyć niepotrzebną replikację:
- Unikaj wysyłania dużej ilości danych naraz za pośrednictwem zdarzeń zdalnych .Zamiast tego wysyłaj tylko niezbędne dane z niższą częstotliwością.Na przykład, dla stanu postaci, powtórz go, gdy zmieni się, a nie za każdym razem, gdy się zmieni.
- Zbierz skomplikowane drzewa instancji tak jak mapy i rozładowuj je w kawałkach, aby rozdzielić pracę replikującą te na wiele ram.
- Wyczyść metadane animacji , szczególnie katalog animacji rygów po ich zaimportowaniu
- Ograniczenie niepotrzebnej replikacji instancji , szczególnie w przypadkach, gdy serwer nie musi mieć wiedzy o tworzonych instancjach.Obejmuje to:
- Efekty wizualne, takie jak wybuch lub eksplozja magicznego zaklęcia.Serwer musi wiedzieć tylko o lokalizacji, aby określić wynik, podczas gdy klienci mogą tworzyć wizualizacje lokalnie.
- Modele widoku przedmiotów w pierwszej osobie.
- Przedmioty przejściowe na klientach zamiast na serwerze.
Zakresy mikroprofilera
Zakres | Powiązane obliczenia |
Pakiety procesowe | Przetwarzanie przychodzących pakietów sieciowych, takich jak wezwania zdarzeń i zmiany właściwości |
Przydzielaj przepustowość i uruchamiaj nadawców | Wydarzenia wychodzące odpowiednie na serwerach |
Zużycie pamięci zasobów
Najwyższy mechanizm wpływu dostępny dla twórców do poprawy zużycia pamięci klienta polega na włączeniu przesyłania instancji.
Streamowanie instancji
Strumieniowanie instancji wybierowo ładowuje części modelu danych, które nie są wymagane, co może doprowadzić do znacznie zmniejszonego czasu obciążenia i zwiększenia zdolności klienta do zapobiegania awariom, gdy znajdzie się pod presją pamięci.
Jeśli napotykasz problemy z pamięcią i masz wyłączoną transmisję instancji, rozważ aktualizację doświadczenia, aby je wspierać, szczególnie jeśli twój świat 3D jest duży.Streamowanie instancji opiera się na odległości w przestrzeni 3D, więc większe światy naturalnie więcej z niego korzystają.
Jeśli transmisja instancji jest włączona, możesz zwiększyć jej agresywność. Na przykład rozważ:
- Zmniejszanie użycia trwałego StreamingIntegrity .
- Zmniejszanie promienia strumieniowania .
Aby uzyskać więcej informacji o opcjach przesyłania i ich korzyściach, zobacz właściwości przesyłania.
Inne powszechne problemy
- Duplikacja zasobów - Pospolity błąd polega na przesłaniu tego samego zasobu wielokrotnie, co prowadzi do różnych identyfikatorów zasobów.Może to doprowadzić do tego, że ta sama treść zostanie zapisana w pamięci wielokrotnie.
- Nadmierna objętość zasobów - Nawet gdy zasoby nie są identyczne, zdarzają się przypadki, w których przegapiane są możliwości ponownego wykorzystania tego samego zasobu i oszczędzania pamięci.
- Pliki audio - Pliki audio mogą być zaskakującym współtwórcą zużycia pamięci, szczególnie jeśli załadujesz je wszystkie do klienta naraz, a nie tylko to, czego potrzebujesz dla części doświadczenia.Dla strategii, patrz Czas ładowania.
- Wysokiej rozdzielczości tekstury - zużycie pamięci graficznej dla tekstury nie jest związane z rozmiarem tekstury na dyskach, ale raczej z liczbą pikseli w teksturze.
- Na przykład tekstura pikselowa 1024x1024 zużywa cztery razy więcej pamięci graficznej niż tekstura 512x512.
- Przesłane do Roblox obrazy są transkodowane do stałego formatu, więc nie ma korzyści z pamięci z przesłaniem obrazów w modelu kolorów związanych z mniejszą ilością bajtów na pikselu.Podobnie, kompresowanie obrazów przed przesłaniem lub usunięciem kanału alfa z obrazów, których nie potrzebujesz, może zmniejszyć rozmiar obrazu na dysku, ale albo nie poprawia, albo tylko minimalnie poprawia zużycie pamięci.Chociaż silnik automatycznie zmniejsza rozdzielczość tekstury na niektórych urządzeniach, zakres zmniejszenia zależy od cech urządzenia, a nadmierna rozdzielczość tekstury nadal może powodować problemy.
- Możesz zidentyfikować zużycie pamięci graficznej dla danego tekstury, rozszerzając kategorię Pamięć graficzna w konsoli programisty .
Złagodzenie
Tylko przesyłaj zasoby raz - Powtórz ten sam identyfikator zasobu między obiektami i zapewnij, że te same zasoby, szczególnie siatki i obrazy, nie są przesyłane wielokrotnie osobno.
Znajdź i napraw zduplikowane zasoby - Poszukaj identycznych części siatki i tekstur, które są przesyłane wielokrotnie z różnymi ID.
- Chociaż nie ma API do wykrywania podobieństwa zasobów automatycznie, możesz zebrać wszystkie ID zasobów obrazu w swoim miejscu (ręcznie lub za pomocą skryptu), pobrać je i porównać je za pomocą zewnętrznych narzędzi do porównywania.
- Dla części siatkowych najlepszą strategią jest wzięcie unikalnych identyfikatorów siatki i zorganizowanie ich według rozmiaru, aby ręcznie zidentyfikować duplikaty.
- Zamiast używać oddzielnych tekstur dla różnych kolorów, przeslij jedną teksturę i użyj właściwości SurfaceAppearance.Color, aby zastosować różne odcienie do niej.
Importuj zasoby na mapie oddzielnie - Zamiast importować całą mapę naraz, importuj i odbuduj zasoby na mapie indywidualnie i odbuduj je.Importer 3D nie dokonuje żadnej de-duplikacji siatek, więc jeśli zaimportujesz dużą mapę z wieloma odrębnymi płytkami podłogowymi, każda z tych płytek zostanie zaimportowana jako odrębny zasób (nawet jeśli są duplikatami).Może to doprowadzić do problemów z wydajnością i pamięcią w dół linii, ponieważ każda siatka jest traktowana jako indywidualna i zajmuje pamięć oraz wezwania do wykonywania.
Ogranicz piksele obrazów do nie więcej niż niezbędnej ilości.Chyba że obraz zajmuje dużą ilość przestrzeni fizycznej na ekranie, zwykle potrzebuje maksymalnie 512x512 pikseli.Większość mniejszych obrazów powinna być mniejsza niż 256x256 pikseli.
Użyj arkuszy obcinających , aby zapewnić maksymalne ponowne wykorzystanie tekstur w mapach 3D.Aby uzyskać kroki i przykłady na temat tworzenia arkuszy obcinających, zobacz Twórz arkusze obcinające.
Możesz również rozważyć użycie arkuszy sprite do ładowania wielu mniejszych obrazów UI jako pojedynczego obrazu.Następnie możesz użyć ImageLabel.ImageRectOffset i ImageLabel.ImageRectSize , aby wyświetlić części arkusza.
Czasy ładowania
Wiele doświadczeń implementuje niestandardowe ekrany ładowania i wykorzystuje metodę ContentProvider:PreloadAsync() w celu żądania zasobów, aby obrazy, dźwięki i siatki były pobierane w tle.
Zaletą tego podejścia jest to, że pozwala ci upewnić się, że ważne części twojego doświadczenia są w pełni załadowane bez wyskakiwania.Jednak powszechnym błędem jest przesadne wykorzystanie tej metody do przedsprzedaży większej liczby zasobów niż są rzeczywiście wymagane.
Przykładem złej praktyki jest ładowanie całej Workspace. Chociaż może to zapobiec pojawieniu się tekstury, znacznie zwiększa czas ładowania.
Zamiast tego używaj tylko ContentProvider:PreloadAsync() w niezbędnych sytuacjach, które obejmują:
- Obrazy na ekranie ładowania.
- Ważne obrazy w menu doświadczeń, takie jak tła przycisków i ikony.
- Ważne zasoby w obszarze startowym lub spawnowania.
Jeśli musisz załadować dużą liczbę zasobów, zalecamy dostarczenie przycisku Pomiń ładowanie .