Czy ktoś może mi krótko wyjaśnić, jak działa ARC? Wiem, że różni się od Garbage Collection, ale zastanawiałem się dokładnie, jak to działa.
Ponadto, jeśli ARC robi to, co robi GC bez ograniczania wydajności, to dlaczego Java używa GC? Dlaczego nie używa również ARC?
objective-c
cocoa-touch
garbage-collection
automatic-ref-counting
użytkownik635064
źródło
źródło
Odpowiedzi:
Każdy nowy programista, który przyjdzie do Objective-C, musi nauczyć się sztywnych zasad, kiedy zachować, zwolnić i automatycznie wydać obiekt. Reguły te określają nawet konwencje nazewnictwa, które implikują zachowanie liczby obiektów zwracanych z metod. Zarządzanie pamięcią w Objective-C staje się drugą naturą, gdy weźmiesz sobie do serca te zasady i konsekwentnie je zastosujesz, ale nawet najbardziej doświadczeni twórcy kakao od czasu do czasu tracą kontrolę.
Dzięki analizatorowi statycznemu Clanga programiści LLVM zdali sobie sprawę, że reguły te są na tyle niezawodne, że mogą zbudować narzędzie do wskazywania wycieków pamięci i nadmiernego wydawania w ścieżkach, które podąża Twój kod.
Kolejnym logicznym krokiem jest automatyczne zliczanie referencji (ARC). Jeśli kompilator rozpoznaje, gdzie należy zachować i zwalniać obiekty, dlaczego nie wstawić tego kodu? Sztywne, powtarzalne zadania są tym, w czym świetnie radzą sobie kompilatorzy i ich bracia. Ludzie zapominają rzeczy i popełniają błędy, ale komputery są znacznie bardziej spójne.
Nie oznacza to jednak, że nie musisz martwić się o zarządzanie pamięcią na tych platformach. Opiszę podstawową kwestię zwrócić uwagę (zachowują cykli) w moją odpowiedź tutaj , co może wymagać trochę myśli na części, aby oznaczyć słabe wskaźniki. Jest to jednak niewielkie w porównaniu do tego, co zyskujesz w ARC.
W porównaniu z ręcznym zarządzaniem pamięcią i zbieraniem pamięci, ARC daje to, co najlepsze z obu światów, eliminując potrzebę pisania kodu zatrzymania / zwolnienia, ale nie widząc profili pamięci zatrzymania i piłokształtnych w środowisku śmieci. Jedynymi zaletami wyrzucania elementów bezużytecznych jest możliwość radzenia sobie z cyklami przechowywania oraz fakt, że przypisywanie właściwości atomowych jest niedrogie (jak omówiono tutaj ). Wiem, że zastępuję cały istniejący kod Mac GC implementacjami ARC.
Jeśli chodzi o to, czy można go rozszerzyć na inne języki, wydaje się, że jest ukierunkowany na system liczenia referencji w Objective-C. Może to być trudne do zastosowania w Javie lub innych językach, ale nie znam wystarczająco dużo szczegółów na temat kompilatora niskiego poziomu, aby dokonać tam ostatecznego stwierdzenia. Biorąc pod uwagę, że Apple jest tym, który popycha ten wysiłek w LLVM, cel C będzie najważniejszy, chyba że inna strona zaangażuje w to znaczne zasoby.
Odsłonięcie tego zszokowanego programisty w WWDC, więc ludzie nie byli świadomi, że coś takiego można zrobić. Z czasem może pojawiać się na innych platformach, ale na razie jest wyłączny dla LLVM i Objective-C.
źródło
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ć:
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.
źródło
foo = nil
.magia
Ale dokładniej ARC działa, robiąc dokładnie to, co zrobiłbyś ze swoim kodem (z pewnymi drobnymi różnicami). ARC to technologia czasu kompilacji, w przeciwieństwie do GC, który jest środowiskiem uruchomieniowym i negatywnie wpłynie na wydajność. ARC będzie śledzić odniesienia do obiektów dla Ciebie i zsyntetyzować metody zachowania / wydania / automatycznego wydawania zgodnie z normalnymi zasadami. Z tego powodu ARC może także wypuszczać rzeczy, gdy tylko nie są już potrzebne, zamiast wrzucać je do puli autorelease wyłącznie dla celów konwencji.
Niektóre inne ulepszenia obejmują zerowanie słabych referencji, automatyczne kopiowanie bloków na stos, przyspieszenie na całym forum (6x dla pul autorelease!).
Bardziej szczegółowa dyskusja na temat tego, jak to wszystko działa, znajduje się w Dokumentach LLVM na ARC.
źródło
Różni się znacznie od śmiecia. Czy widziałeś ostrzeżenia, które mówią, że możesz przeciekać przedmioty na różnych liniach? Te instrukcje mówią nawet, w której linii przypisałeś obiekt. Zostało to zrobione krok dalej i teraz można wstawiać
retain
/release
instrukcje w odpowiednich miejscach, lepiej niż większość programistów, prawie w 100% przypadków. Czasami zdarzają się dziwne przypadki zachowanych obiektów, z którymi musisz sobie pomóc.źródło
Bardzo dobrze wyjaśnione w dokumentacji dla deweloperów Apple. Przeczytaj „Jak działa ARC”
Poznać Diff. między Garbage collection a ARC: Przeczytaj to
źródło
ARC to funkcja kompilatora, która zapewnia automatyczne zarządzanie pamięcią obiektów.
Zamiast pamiętać, kiedy używać
retain, release
,autorelease
ARC ocenia wymagania dotyczące żywotności obiektów i automatycznie wstawia odpowiednie wezwania do zarządzania pamięcią w czasie kompilacji. Kompilator generuje również odpowiednie metody dealloc.Kompilator wstawia niezbędne
retain/release
wywołania w czasie kompilacji, ale te wywołania są wykonywane w czasie wykonywania, tak jak każdy inny kod.Poniższy schemat daje lepsze zrozumienie działania ARC.
Ci, którzy są nowi w tworzeniu systemu iOS i nie mają doświadczenia w pracy z celem C. Aby zapoznać się z zarządzaniem pamięcią, zapoznaj się z dokumentacją Apple w Przewodniku programowania zaawansowanego zarządzania pamięcią.
źródło