ARC po prostu odtwarza stare zachowanie / zwolnienie (MRC), a kompilator zastanawia się, kiedy wywołać zachowanie / zwolnienie. Będzie miał tendencję do wyższej wydajności, niższego zużycia pamięci szczytowej i bardziej przewidywalnej wydajności niż system GC.
Z drugiej strony niektóre typy struktury danych nie są możliwe w przypadku ARC (lub MRC), podczas gdy GC może je obsłużyć.
Na przykład, jeśli masz klasę o nazwie węzeł, a węzeł ma macierz potomną NSA i pojedyncze odniesienie do jej elementu nadrzędnego, który „po prostu działa” z GC. Z ARC (i manualnym zliczaniem referencji) masz problem. Każdy węzeł będzie przywoływany zarówno od jego dzieci, jak i od jego rodzica.
Lubić:
A -> [B1, B2, B3]
B1 -> A, B2 -> A, B3 -> A
Wszystko jest w porządku, gdy używasz A (powiedzmy przez zmienną lokalną).
Kiedy to zrobisz (i B1 / B2 / B3), system GC ostatecznie zdecyduje się spojrzeć na wszystko, co może znaleźć, począwszy od stosu i rejestrów procesora. Nigdy nie znajdzie A, B1, B2, B3, więc sfinalizuje je i przetworzy pamięć na inne obiekty.
Gdy użyjesz ARC lub MRC i skończysz z A, jego liczba zwrotna wynosi 3 (B1, B2 i B3 odnoszą się do niego), a B1 / B2 / B3 będą miały liczbę referencyjną równą 1 (NSArray A zawiera jedno odniesienie do każdy). Tak więc wszystkie te obiekty pozostają żywe, mimo że nic nigdy nie może ich użyć.
Częstym rozwiązaniem jest stwierdzenie, że jedno z tych odniesień musi być słabe (nie przyczyniać się do liczenia odniesień). Będzie to działać w przypadku niektórych wzorców użytkowania, na przykład, jeśli odwołujesz się do B1 / B2 / B3 tylko przez A. Jednak w innych wzorcach nie działa. Na przykład, jeśli czasami trzymasz się B1 i spodziewasz się wspiąć przez wskaźnik nadrzędny i znaleźć A. Słabe odniesienie, jeśli tylko trzymasz się B1, A może (i normalnie) wyparuje i weź B2 i B3 z tym.
Czasami nie jest to problem, ale bardzo przydatne i naturalne sposoby pracy ze złożonymi strukturami danych są bardzo trudne w użyciu z ARC / MRC.
Tak więc ARC atakuje ten sam rodzaj problemów, co cele GC. Jednak ARC działa na bardziej ograniczonym zestawie wzorców użytkowania niż GC, więc jeśli weźmiesz język GC (jak Java) i wszczepisz na nim coś takiego jak ARC, niektóre programy już nie będą działać (lub przynajmniej wygenerują tony porzuconej pamięci i może powodować poważne problemy z zamianą lub brak pamięci lub przestrzeni wymiany).
Można również powiedzieć, że ARC kładzie większy nacisk na wydajność (a może przewidywalność), podczas gdy GC kładzie większy nacisk na bycie rozwiązaniem ogólnym. W rezultacie GC ma mniej przewidywalne zapotrzebowanie na procesor / pamięć i niższą wydajność (zwykle) niż ARC, ale może obsłużyć dowolny wzorzec użytkowania. ARC będzie działać znacznie lepiej w przypadku wielu powszechnych wzorców użytkowania, ale w przypadku kilku (prawidłowych!) Wzorców przewróci się i umrze.