2011-06-21 2 views
8

Mam intensywną pamięć iOS i pracuję nad upewnieniem się, że użycie pamięci nie rośnie z czasem. Moja aplikacja ma "główny" kontekst, który działa przez cały okres istnienia aplikacji, a inne mniejsze konteksty są od czasu do czasu odsłaniane dla zadań wykonywanych w tle.Unikanie gromadzenia się zarejestrowanych obiektów (memleak) w NSManagedObjectContext

Jedną z rzeczy, które zauważyłem jest to, że obiekty NSManagedObject wydają się pozostawać zarejestrowane w głównym kontekście długoterminowym i jedynym sposobem na odzyskanie całej pamięci związanej z odciąganiem obiektów z DB jest wywołanie [NSManagedObjectContext reset].

To oczywiście powoduje spadek zużycia pamięci, ponieważ wszystkie zarejestrowane obiekty z ostatnio zamkniętych widoków listy są prawidłowo usuwane z pamięci, jednak jest to denerwujące, ponieważ właśnie unieważniłeś każdy zarejestrowany obiekt w tym kontekście, nadal mają odniesienie do (tj. obiektów, do których odwołują się widoki, które są nadal otwarte), i musisz teraz ponownie pobrać wszystkie te obiekty z bazy danych, aby uniknąć wyjątków dostępu do unieważnionego obiektu.

Czy jest to jedyny sposób wypłukiwania zarejestrowanego zestawu obiektów z obiektu NSManagedObjectContext, czy istnieje lepszy sposób, w jaki pomyślnie usuwa wszystkie zarejestrowane obiekty, do których nie ma już odniesienia, ale nie powoduje unieważnienia wszystkich obiektów NSManagedObject wciąż żywy?

Odpowiedz

12

NSManagedObjectContext ma wewnętrzną pamięć podręczną wiersza, a jedynym sposobem, aby to wyczyścić, jest zresetowanie kontekstu. Jeśli masz problemy z pamięcią, możesz pomóc:

  • Zarządzane obiekty zachowują powiązane obiekty. Jeśli zarządzałeś obiektem A, do którego odwołuje się relacja z innego zarządzanego obiektu B, obiekt A pozostanie w pamięci nawet po opublikowaniu wszystkich odniesień do niego. Nie zostanie ona faktycznie zwolniona, dopóki obiekt nie zostanie zwolniony lub nie zostanie ponownie zarzucony, ponieważ nadal będzie zachowywany przez B.
  • Jednym ze sposobów radzenia sobie z tym (i innymi problemami z pamięcią) jest wywołanie refreshObject:mergeChanges: na MOC dla obiektów, których obecnie nie używasz, z drugim argumentem ustawionym na NO. To powoduje ponowne uszkodzenie obiektu, tj. Sprawia, że ​​obiekt wraca do początkowego stanu "błędu", rozładowując jego wartości właściwości i relacje. W przypadku A i B z wcześniejszym błędem B ujawniłoby związek z A. Pamiętaj, że utracisz niezapisane zmiany na B, więc upewnij się, że zapisałeś je w pierwszej kolejności, jeśli to konieczne.
  • Jeśli zarządzane obiekty zawierają jakiekolwiek duże dane binarne, spróbuj przenieść te dane do oddzielnej jednostki lub całkowicie poza Danymi podstawowymi, aby uniknąć ładowania ich do pamięci, gdy nie są potrzebne.
  • reset w MOC jest w zasadzie opcją jądrową, jeśli chodzi o zarządzanie pamięcią danych podstawowych. Jest niezwykle skuteczny, ale jak się okazało, może być bardzo niebezpieczny. Najlepiej tego unikać, chyba że nie używasz już żadnych przedmiotów załadowanych z MOC.
+0

Hej Tom - dzięki za tę wspaniałą odpowiedź. Spośród wszystkich opcji, jedyne, o którym myślałem, że może pomóc, to 'refreshObject: mergeChanges:' one, i kiedy wypróbowałem go, wywołując go na wszystkich obiektach w widoku listy, gdy widok listy został zniszczony, niestety nie wydawało się mieć wielkiego wpływu. Zgaduję, że pamięć podręczna wiersza jest tym, co pochłania wszystkie pamięci, więc jeśli nie ma innego sposobu na wyczyszczenie pamięci podręcznej wiersza, domyślam się, że nadal będę musiał przejść trasę 'reset'. Bummer :( – glenc

+0

Czy otrzymujesz ostrzeżenia o pamięci? Nigdy nie powiedziałeś, jeśli nie, resetowanie kontekstu jest zupełnie niepotrzebne –

+0

Tak, otrzymuję ostrzeżenia o pamięci.To zależy od wielkości używanej bazy danych, ale tak, zdecydowanie się zdarzają. – glenc