Rozwiązywanie problemów z LMK w grze w Unity to proces systematyczny:

Uzyskiwanie zrzutu pamięci
Użyj profilera Unity, aby uzyskać migawkę pamięci zarządzanej przez Unity. Ilustracja 2 przedstawia warstwy zarządzania pamięcią, których Unity używa do obsługi pamięci w Twojej grze.

Pamięć zarządzana
Zarządzanie pamięcią w Unity wykorzystuje kontrolowaną warstwę pamięci, która używa zarządzanego stogu i mechanizmu odśmiecania do automatycznego przydzielania i przypisywania pamięci. System zarządzania pamięcią to środowisko skryptowe C# oparte na Mono lub IL2CPP. Zaletą zarządzanego systemu pamięci jest to, że wykorzystuje on moduł odśmiecania do automatycznego zwalniania przydzielonej pamięci.
Pamięć niezarządzana w C#
Niezarządzana warstwa pamięci C# zapewnia dostęp do natywnej warstwy pamięci, umożliwiając precyzyjną kontrolę nad przydzielaniem pamięci podczas korzystania z kodu C#. Dostęp do tej warstwy zarządzania pamięcią można uzyskać za pomocą przestrzeni nazw Unity.Collections i funkcji takich jak UnsafeUtility.Malloc i UnsafeUtility.Free.
Pamięć natywna
Wewnętrzny rdzeń C/C++ Unity korzysta z natywnego systemu pamięci do zarządzania scenami, zasobami, interfejsami API grafiki, sterownikami, podsystemami i buforami wtyczek. Bezpośredni dostęp jest ograniczony, ale możesz bezpiecznie manipulować danymi za pomocą interfejsu API C# Unity i korzystać z wydajnego kodu natywnego. Pamięć natywna rzadko wymaga bezpośredniej interakcji, ale możesz monitorować jej wpływ na wydajność za pomocą profilera i dostosowywać ustawienia, aby ją zoptymalizować.
Pamięć nie jest współdzielona między kodem C# a kodem natywnym, jak pokazano na rysunku 3. Dane wymagane przez C# są przydzielane w zarządzanej przestrzeni pamięci za każdym razem, gdy są potrzebne.
Aby kod zarządzanej gry (C#) miał dostęp do danych z pamięci natywnej silnika, na przykład wywołanie GameObject.transform powoduje wywołanie natywne, które uzyskuje dostęp do danych z pamięci w obszarze natywnym, a następnie zwraca wartości do C# za pomocą powiązań. Powiązania zapewniają odpowiednie konwencje wywoływania dla każdej platformy i obsługują automatyczne przekształcanie typów zarządzanych na ich natywne odpowiedniki.
Dzieje się tak tylko za pierwszym razem, ponieważ zarządzana powłoka do uzyskiwania dostępu do właściwości transform jest zachowywana w kodzie natywnym. Buforowanie właściwości transform może zmniejszyć liczbę wywołań w obie strony między kodem zarządzanym a natywnym, ale przydatność buforowania zależy od tego, jak często właściwość jest używana. Pamiętaj też, że podczas korzystania z tych interfejsów API Unity nie kopiuje części pamięci natywnej do pamięci zarządzanej.

Więcej informacji znajdziesz w artykule wprowadzającym do pamięci w Unity.
Ustalenie budżetu pamięci jest też kluczowe, aby gra działała płynnie. Wdrożenie systemu analitycznego lub raportującego zużycie pamięci zapewnia, że każda nowa wersja nie przekracza budżetu pamięci. Kolejną strategią, która pozwala lepiej poznać grę, jest zintegrowanie testów w trybie odtwarzania z ciągłą integracją (CI), aby weryfikować zużycie pamięci w określonych obszarach gry.
Zarządzanie zasobami
Jest to najbardziej znacząca i najbardziej przydatna część informacji o zużyciu pamięci. Profil jak najszybciej.
Wykorzystanie pamięci w grach na Androida może się znacznie różnić w zależności od typu gry, liczby i rodzajów zasobów oraz strategii optymalizacji pamięci. Do najczęstszych czynników wpływających na zużycie pamięci należą jednak tekstury, siatki, pliki audio, shadery, animacje i skrypty.
Wykrywanie zduplikowanych komponentów
Pierwszym krokiem jest wykrycie źle skonfigurowanych zasobów i zduplikowanych zasobów za pomocą profilera pamięci, narzędzia do tworzenia raportów o kompilacji lub audytora projektu.
Tekstury
Przeanalizuj obsługę urządzeń w swojej grze i wybierz odpowiedni format tekstury. Pakiety tekstur dla urządzeń z wyższej i niższej półki możesz podzielić za pomocą Play Asset Delivery, adresowania lub bardziej ręcznego procesu z użyciem AssetBundle.
Postępuj zgodnie z najbardziej znanymi rekomendacjami dostępnymi w artykule Optymalizacja wydajności gry mobilnej i w poście na forum Optymalizacja ustawień importowania tekstur w Unity. Następnie wypróbuj te rozwiązania:
Kompresuj tekstury za pomocą formatów ASTC, aby zmniejszyć zużycie pamięci, i eksperymentuj z wyższym współczynnikiem bloków, np. 8x8.
Jeśli wymagane jest użycie ETC2, spakuj tekstury w Atlas. Umieszczenie wielu tekstur w jednej teksturze zapewnia jej rozmiar będący potęgą liczby 2, może zmniejszyć liczbę wywołań rysowania i przyspieszyć renderowanie.
Zoptymalizuj format i rozmiar tekstury RenderTarget. Unikaj niepotrzebnie wysokiej rozdzielczości tekstur. Używanie mniejszych tekstur na urządzeniach mobilnych oszczędza pamięć.
Aby zaoszczędzić pamięć tekstur, użyj pakowania kanałów tekstur.
Siatki i modele
Zacznij od sprawdzenia podstawowych ustawień (strona 27) i zweryfikuj te ustawienia importowania siatki:
- Scalanie nadmiarowych i mniejszych siatek.
- Zmniejsz liczbę wierzchołków obiektów w scenach (np. statycznych lub odległych).
- Generowanie grup poziomu szczegółowości (LOD) dla komponentów o dużej liczbie geometrii.
Materiały i cieniowanie
- Usuwaj nieużywane warianty cieniowania programowo podczas procesu kompilacji.
- Łącz często używane warianty shaderów w super shadery, aby uniknąć powielania shaderów.
- Włącz dynamiczne wczytywanie shaderów, aby zmniejszyć dużą ilość pamięci zajmowaną przez wstępnie wczytane shadery w pamięci VRAM/RAM. Zwróć jednak uwagę, czy kompilacja shadera nie powoduje problemów z płynnością.
- Używaj dynamicznego wczytywania cieniowania, aby zapobiec wczytywaniu wszystkich wariantów. Więcej informacji znajdziesz w poście na blogu Improvements to shader build times and memory usage (w języku angielskim).
- Prawidłowo korzystaj z instancji materiałów, używając
MaterialPropertyBlocks
.
Audio
Zacznij od sprawdzenia podstawowych ustawień (strona 41) i zweryfikuj te ustawienia importowania siatki:
- Usuń nieużywane lub zbędne odwołania do
AudioClip
, gdy korzystasz z zewnętrznych silników audio, takich jak FMOD czy Wwise. - Wstępne wczytywanie danych audio. Wyłącz wstępne wczytywanie klipów, które nie są od razu wymagane podczas działania lub uruchamiania sceny. Pomaga to zmniejszyć obciążenie pamięci podczas inicjowania sceny.
Animacje
- Dostosuj ustawienia kompresji animacji w Unity, aby zminimalizować liczbę klatek kluczowych i wyeliminować zbędne dane.
- Redukcja klatek kluczowych: automatyczne usuwanie niepotrzebnych klatek kluczowych.
- Kompresja kwaternionowa: kompresuje dane rotacji, aby zmniejszyć zużycie pamięci.
Ustawienia kompresji możesz dostosować w sekcji Ustawienia importowania animacji na karcie Rig lub Animacja.
Używaj ponownie klipów animacji zamiast je duplikować w przypadku różnych obiektów.
Używaj kontrolerów zastępujących animatora, aby ponownie wykorzystać kontroler animatora i zastąpić konkretne klipy różnymi postaciami.
Wypiekanie animacji opartych na fizyce: jeśli animacje są oparte na fizyce lub generowane proceduralnie, wypiecz je w klipach animacji, aby uniknąć obliczeń w czasie działania.
Optymalizacja szkieletu: używaj mniejszej liczby kości w szkielecie, aby zmniejszyć złożoność i zużycie pamięci.
- Unikaj zbyt dużej liczby kości w przypadku małych lub statycznych obiektów.
- Jeśli niektóre kości nie są animowane lub nie są potrzebne, usuń je z riggu.
Skróć klip animacji.
- Przytnij klipy animacji, aby zawierały tylko niezbędne klatki. Unikaj przechowywania nieużywanych lub zbyt długich animacji.
- Zamiast tworzyć długie klipy z powtarzającymi się ruchami, używaj animacji w pętli.
Upewnij się, że tylko 1 komponent animacji jest dołączony lub aktywowany. Na przykład wyłącz lub usuń komponenty Animacja starszego typu, jeśli używasz Animatora.
Unikaj używania Animatora, jeśli nie jest to konieczne. W przypadku prostych efektów wizualnych użyj bibliotek animacji lub zaimplementuj efekt wizualny w skrypcie. System animatora może zużywać dużo zasobów, zwłaszcza na urządzeniach mobilnych z niższej półki.
W przypadku dużej liczby animacji używaj systemu zadań, ponieważ został on całkowicie przeprojektowany, aby zużywać mniej pamięci.
Oświetlenie
Gdy wczytywane są nowe sceny, zasoby są dodawane jako zależności. Jednak bez odpowiedniego zarządzania cyklem życia komponentów te zależności nie są monitorowane przez liczniki odwołań. W rezultacie komponenty mogą pozostać w pamięci nawet po zwolnieniu nieużywanych scen, co powoduje fragmentację pamięci.
- Używaj puli obiektów Unity, aby ponownie wykorzystywać instancje GameObject w przypadku powtarzających się elementów rozgrywki, ponieważ pula obiektów używa stosu do przechowywania kolekcji instancji obiektów do ponownego wykorzystania i nie jest bezpieczna dla wątków. Minimalizacja
Instantiate
iDestroy
zwiększa wydajność procesora i stabilność pamięci. - Usuwanie komponentów:
- Strategicznie zwalniaj zasoby w mniej krytycznych momentach, np. na ekranach powitalnych lub ekranach wczytywania.
- Częste używanie
Resources.UnloadUnusedAssets
powoduje skoki obciążenia procesora ze względu na duże operacje monitorowania zależności wewnętrznych. - Sprawdź, czy w profilu GC.MarkDependencies nie występują duże skoki wykorzystania procesora.
Usuń lub zmniejsz częstotliwość jego wykonywania i zamiast polegać na wszechstronnym poleceniu
Resources.UnloadUnusedAssets()
, ręcznie zwalniaj określone zasoby za pomocą polecenia Resources.UnloadAsset.
- Zamiast ciągle używać funkcji Resources.UnloadUnusedAssets, restrukturyzuj sceny.
- Wywołanie funkcji
Resources.UnloadUnusedAssets()
w przypadkuAddressables
może spowodować nieumyślne zwolnienie dynamicznie załadowanych pakietów. Starannie zarządzaj cyklem życia zasobów ładowanych dynamicznie.
Różne
Fragmentacja spowodowana przejściami między scenami – gdy wywoływana jest metoda
Resources.UnloadUnusedAssets()
, Unity wykonuje te czynności:- Zwalnia pamięć na potrzeby komponentów, które nie są już używane.
- Przeprowadza operację podobną do odśmiecania, aby sprawdzić stertę obiektów zarządzanych i natywnych pod kątem nieużywanych zasobów i je zwalniać.
- Czyści pamięć tekstur, siatek i zasobów, pod warunkiem że nie ma aktywnych plików referencyjnych.
AssetBundle
lubAddressable
– wprowadzanie zmian w tym obszarze jest złożone i wymaga wspólnego wysiłku zespołu w celu wdrożenia strategii. Gdy jednak opanujesz te strategie, znacznie poprawisz wykorzystanie pamięci, zmniejszysz rozmiar pobierania i obniżysz koszty chmury. Więcej informacji o zarządzaniu zasobami w Unity znajdziesz w artykuleAddressables
.Scentralizowane zależności udostępnione: grupuj udostępnione zależności, takie jak shadery, tekstury i czcionki, w dedykowane pakiety lub
Addressable
grupy. Pozwala to uniknąć duplikowania i zapewnia efektywne zwalnianie niepotrzebnych zasobów.Używaj
Addressables
do śledzenia zależności – Addressables upraszcza wczytywanie i zwalnianie, a także może automatycznie zwalniać zależności, do których nie ma już odwołań. Przejście naAddressables
w zarządzaniu treściami i rozwiązywaniu zależności może być dobrym rozwiązaniem w zależności od konkretnego przypadku gry. Analizuj łańcuchy zależności za pomocą narzędzia Analyze, aby wykrywać niepotrzebne duplikaty lub zależności. Jeśli używasz pakietów AssetBundle, możesz też skorzystać z narzędzi do danych Unity.TypeTrees
– jeśliAddressables
iAssetBundles
w Twojej grze są tworzone i wdrażane przy użyciu tej samej wersji Unity co odtwarzacz i nie wymagają zgodności wstecznej z innymi wersjami odtwarzacza, możesz wyłączyć zapisywanieTypeTree
, co powinno zmniejszyć rozmiar pakietu i zajętość pamięci przez obiekty plików serializowanych. Zmodyfikuj proces kompilacji w ustawieniu pakietu lokalnego Addressables ContentBuildFlags, aby ustawić wartość DisableWriteTypeTree.
Pisanie kodu przyjaznego dla mechanizmu odśmiecania pamięci
Unity wykorzystuje odśmiecanie do zarządzania pamięcią poprzez automatyczne identyfikowanie i zwalnianie nieużywanej pamięci. Chociaż odśmiecanie pamięci jest niezbędne, może powodować problemy z wydajnością (np. skoki liczby klatek na sekundę), jeśli nie jest prawidłowo obsługiwane, ponieważ ten proces może na chwilę wstrzymać grę, co prowadzi do problemów z wydajnością i nieoptymalnego komfortu użytkownika.
Przydatne techniki zmniejszania częstotliwości przydzielania pamięci na stercie zarządzanej znajdziesz w podręczniku Unity, a przykłady – w UnityPerformanceTuningBible na stronie 271.
Zmniejsz przydziały modułu odśmiecania:
- Unikaj LINQ, wyrażeń lambda i zamknięć, które przydzielają pamięć sterty.
- W przypadku ciągów znaków, które można modyfikować, używaj
StringBuilder
zamiast łączenia ciągów. - Używaj ponownie kolekcji, wywołując
COLLECTIONS.Clear()
zamiast tworzyć je od nowa.
Więcej informacji znajdziesz w e-booku Ultimate Guide to Profiling Unity Games (Kompletny przewodnik po profilowaniu gier na platformie Unity).
Zarządzanie aktualizacjami obszaru interfejsu:
- Dynamiczne zmiany elementów interfejsu – gdy elementy interfejsu, takie jak tekst, obraz lub właściwości
RectTransform
, są aktualizowane (np. zmiana treści tekstu, zmiana rozmiaru elementów lub animowanie pozycji), silnik może przydzielać pamięć obiektom tymczasowym. - Przydzielanie ciągów tekstowych – elementy interfejsu, takie jak tekst, często wymagają aktualizacji ciągów tekstowych, ponieważ w większości języków programowania są one niezmienne.
- Zmiany w obszarze roboczym – gdy coś w obszarze roboczym się zmieni (np. rozmiar, włączanie i wyłączanie elementów lub modyfikowanie właściwości układu), cały obszar roboczy lub jego część może zostać oznaczony jako zmieniony i przebudowany. Może to spowodować utworzenie tymczasowych struktur danych (np. danych siatki, buforów wierzchołków lub obliczeń układu), co zwiększa ilość generowanych nieużywanych danych.
- Złożone lub częste aktualizacje – jeśli obszar roboczy zawiera dużą liczbę elementów lub jest często aktualizowany (np. co klatkę), te przebudowy mogą prowadzić do znacznego zużycia pamięci.
- Dynamiczne zmiany elementów interfejsu – gdy elementy interfejsu, takie jak tekst, obraz lub właściwości
Włącz przyrostowe odśmiecanie pamięci, aby zmniejszyć duże skoki zbierania śmieci przez rozłożenie czyszczenia przydziałów na wiele klatek. profilu, aby sprawdzić, czy ta opcja poprawia wydajność gry i zajętość pamięci.
Jeśli gra wymaga kontrolowanego podejścia, ustaw ręczny tryb odśmiecania. Następnie, gdy poziom się zmieni lub w innym momencie, gdy nie ma aktywnej rozgrywki, wywołaj odśmiecanie pamięci.
Wywołuj ręczne wywołania odśmiecania GC.Collect() w przypadku przejść między stanami gry (np. zmiany poziomu).
Optymalizuj tablice, zaczynając od prostych praktyk kodowania, a w razie potrzeby używaj tablic natywnych lub innych natywnych kontenerów w przypadku dużych tablic.
Monitoruj obiekty zarządzane za pomocą narzędzi takich jak Unity Memory Profiler, aby śledzić odwołania do obiektów niezarządzanych, które utrzymują się po zniszczeniu.
Aby skorzystać z automatycznego podejścia, użyj znacznika profilowania i prześlij go do narzędzia do raportowania skuteczności.
Unikanie wycieków pamięci i fragmentacji
Wycieki pamięci
W kodzie C# po zniszczeniu obiektu Unity odwołanie do niego nadal istnieje, a w pamięci pozostaje zarządzany obiekt otoki, czyli zarządzana powłoka. Pamięć natywna powiązana z odwołaniem jest zwalniana, gdy scena jest zwalniana lub gdy obiekt GameObject, do którego jest dołączona pamięć, lub dowolny z jego obiektów nadrzędnych jest niszczony za pomocą metody Destroy()
. Jeśli jednak inne odwołania do sceny lub obiektu GameObject nie zostały wyczyszczone, pamięć zarządzana może pozostać jako obiektwyciekłej powłoki. Więcej informacji o obiektach powłoki zarządzanej znajdziesz w podręczniku Obiekty powłoki zarządzanej.
Wycieki pamięci mogą być też spowodowane subskrypcjami zdarzeń, funkcjami lambda i domknięciami, łączeniem ciągów znaków oraz nieprawidłowym zarządzaniem obiektami z puli:
- Aby zacząć, zapoznaj się z artykułem Wykrywanie wycieków pamięci, aby prawidłowo porównywać migawki pamięci Unity.
- Sprawdź subskrypcje zdarzeń i wycieki pamięci. Jeśli obiekty subskrybują zdarzenia (np. za pomocą delegatów lub UnityEvents), ale nie anulują subskrypcji przed zniszczeniem, menedżer zdarzeń lub wydawca może zachować odniesienia do tych obiektów. Zapobiega to usunięciu tych obiektów przez mechanizm odśmiecania, co prowadzi do wycieków pamięci.
- Monitoruj zdarzenia klasy globalnej lub pojedynczej, które nie są wyrejestrowywane podczas niszczenia obiektu. Na przykład anuluj subskrypcję lub odłącz delegatów w destruktorach obiektów.
- Upewnij się, że zniszczenie obiektów z puli całkowicie unieważnia odwołania do komponentów siatki tekstowej, tekstur i nadrzędnych obiektów GameObject.
- Pamiętaj, że podczas porównywania zrzutów z Unity Memory Profiler i obserwowania różnicy w zużyciu pamięci bez wyraźnego powodu różnica może być spowodowana przez sterownik graficzny lub sam system operacyjny.
fragmentacja pamięci,
Fragmentacja pamięci występuje, gdy wiele małych przydziałów jest zwalnianych w losowej kolejności. Pamięć sterty jest przydzielana sekwencyjnie, co oznacza, że nowe bloki pamięci są tworzone, gdy poprzedni blok się wyczerpie. W konsekwencji nowe obiekty nie wypełniają pustych obszarów starych fragmentów, co prowadzi do fragmentacji. Dodatkowo duże tymczasowe przydziały mogą powodować trwałą fragmentację przez cały czas trwania sesji gry.
Problem ten jest szczególnie dotkliwy, gdy krótkotrwałe duże przydziały są dokonywane w pobliżu przydziałów długotrwałych.
Grupuj przydziały na podstawie ich czasu życia. Najlepiej, aby przydziały o długim czasie życia były tworzone razem na wczesnym etapie cyklu życia aplikacji.
Obserwatorzy i menedżerowie wydarzeń
- Oprócz problemu wspomnianego w sekcji (Wycieki pamięci)77 wycieki pamięci mogą z czasem przyczyniać się do fragmentacji, pozostawiając nieużywaną pamięć przydzieloną do obiektów, które nie są już używane.
- Upewnij się, że zniszczenie obiektów z puli całkowicie unieważnia odwołania do komponentów siatki tekstowej, tekstur i nadrzędnego elementu
GameObjects
. - Menedżerowie wydarzeń często tworzą i przechowują listy lub słowniki, aby zarządzać subskrypcjami wydarzeń. Jeśli te obszary pamięci rosną i się zmniejszają dynamicznie w czasie działania programu, mogą przyczyniać się do fragmentacji pamięci z powodu częstego przydzielania i zwalniania pamięci.
Kod
- Korutyny czasami przydzielają pamięć, czego można łatwo uniknąć, zapisując w pamięci podręcznej instrukcję zwracania IEnumerator zamiast deklarować nową za każdym razem.
- Stale monitoruj stany cyklu życia obiektów w puli, aby uniknąć przechowywania
UnityEngine.Object
odwołań do nieistniejących obiektów.
Zasoby
- W przypadku gier opartych na tekście używaj dynamicznych systemów rezerwowych, aby uniknąć wstępnego wczytywania wszystkich czcionek w przypadku wielu języków.
- Uporządkuj komponenty (np. tekstury i cząsteczki) według typu i oczekiwanego cyklu życia.
- Kompresuj komponenty z atrybutami nieaktywnego cyklu życia, takie jak nadmiarowe obrazy interfejsu i statyczne siatki.
Alokacje oparte na okresie ważności
- Na początku cyklu życia aplikacji przydzielaj zasoby o długim okresie istnienia, aby zapewnić kompaktowe przydziały.
- W przypadku struktur danych wymagających dużej ilości pamięci lub tymczasowych (np. klastrów fizycznych) używaj NativeCollections lub niestandardowych alokatorów.
Działanie związane z pamięcią kodu i plików wykonywalnych
Na wykorzystanie pamięci wpływają też pliki wykonywalne gry i wtyczki.
Metadane IL2CPP
IL2CPP generuje metadane dla każdego typu (np. klas, typów ogólnych i delegatów) w czasie kompilacji, które są następnie używane w czasie działania do odbicia, sprawdzania typu i innych operacji specyficznych dla czasu działania. Te metadane są przechowywane w pamięci i mogą mieć znaczący wpływ na całkowity rozmiar pamięci aplikacji. Pamięć podręczna metadanych IL2CPP ma znaczący wpływ na czas inicjowania i wczytywania. Dodatkowo IL2CPP nie usuwa duplikatów niektórych elementów metadanych (np. typów ogólnych lub informacji serializowanych), co może powodować nadmierne zużycie pamięci. Problem ten jest dodatkowo potęgowany przez powtarzające się lub zbędne użycie typów w projekcie.
Metadane IL2CPP można zmniejszyć przez:
- Unikaj używania interfejsów API odbicia, ponieważ mogą one w znacznym stopniu przyczyniać się do alokacji metadanych IL2CPP.
- Wyłączanie wbudowanych pakietów
- Wdrożenie w Unity 2022 pełnego udostępniania ogólnego, co powinno pomóc zmniejszyć obciążenie spowodowane przez typy ogólne. Aby jednak jeszcze bardziej ograniczyć alokacje, zmniejsz użycie typów ogólnych.
Usuwanie kodu
Oprócz zmniejszenia rozmiaru kompilacji usuwanie kodu zmniejsza też zużycie pamięci. Podczas kompilowania z użyciem backendu skryptowego IL2CPP usuwanie zarządzanego kodu bajtowego (które jest domyślnie aktywowane) usuwa nieużywany kod z zarządzanych zestawów. Proces ten polega na zdefiniowaniu zestawów głównych, a następnie na użyciu statycznej analizy kodu w celu określenia, jakiego innego kodu zarządzanego używają te zestawy główne. Wszelki nieosiągalny kod jest usuwany. Więcej informacji o usuwaniu zarządzanego kodu znajdziesz w artykule na blogu TTales from the optimization trenches: Better managed code stripping with Unity 2020 LTS (w języku angielskim) oraz w dokumentacji Usuwanie zarządzanego kodu.
Natywne alokatory
Eksperymentuj z natywnymi alokatorami pamięci, aby dostroić alokatory pamięci. Jeśli gra ma mało pamięci, używaj mniejszych bloków pamięci, nawet jeśli wiąże się to z wolniejszymi alokatorami. Więcej informacji znajdziesz w przykładzie dynamicznego alokatora sterty.
Zarządzanie wtyczkami natywnymi i pakietami SDK
Znajdź problematyczną wtyczkę – usuń każdą wtyczkę i porównaj zrzuty pamięci gry. Obejmuje to wyłączenie wielu funkcji kodu za pomocą opcji Scripting Define Symbols i refaktoryzację ściśle powiązanych klas za pomocą interfejsów. Zaznacz Ulepsz swój kod dzięki wzorcom programowania gier, aby ułatwić proces wyłączania zależności zewnętrznych bez uniemożliwiania gry.
Skontaktuj się z autorem wtyczki lub pakietu SDK – większość wtyczek nie jest dostępna na licencji open source.
Odtwórz wykorzystanie pamięci przez wtyczkę – możesz napisać prostą wtyczkę (użyj tego pluginu Unity jako odniesienia), która przydziela pamięć. Sprawdź zrzuty pamięci w Android Studio (ponieważ Unity nie śledzi tych alokacji) lub wywołaj klasę
MemoryInfo
i metodęRuntime.totalMemory()
w tym samym projekcie.
Wtyczka Unity przydziela pamięć Javy i pamięć natywną. Aby to zrobić:
Java
byte[] largeObject = new byte[1024 * 1024 * megaBytes];
list.add(largeObject);
Reklamy natywne
char* buffer = new char[megabytes * 1024 * 1024];
// Random data to fill the buffer
for (int i = 1; i < megabytes * 1024 * 1024; ++i) {
buffer[i] = 'A' + (i % 26); // Fill with letters A-Z
}