Do ARC czy nie do ARC? Jakie są wady i zalety? [Zamknięte]

113

Nie korzystałem jeszcze z ARC, ponieważ większość kodu w projekcie, nad którym obecnie pracuję, została napisana przed iOS 5.0.

Zastanawiałem się tylko, czy wygoda braku zachowywania / publikowania ręcznie (i prawdopodobnie bardziej niezawodnego kodu, który jest wynikiem?) Przewyższa jakikolwiek „koszt” korzystania z ARC? Jakie są Twoje doświadczenia z ARC i czy możesz to polecić?

Więc:

  • Jakie korzyści może przynieść ARC do projektu?
  • Czy ARC ma koszt podobny do zbierania śmieci w Javie?
  • Czy korzystałeś z ARC, a jeśli tak, to w jaki sposób je znalazłeś?
Simon Withington
źródło
Na iPadzie / iOS nie ma wyrzucania elementów bezużytecznych. Mówisz o OS X?
dasblinkenlight
1
Przepraszam, używam terminów Java nie na miejscu. Mam na myśli to, że dzięki ARC obiekty mogą być przechowywane w pamięci dłużej niż to konieczne, a następnie zwolnione jako grupa w puli automatycznie zwalnianej jakiś czas później. Jest to efekt tego, że są one później przechowywane i zwalniane z innymi obiektami, podobnie jak w przypadku czyszczenia pamięci w Javie, o którym mówię.
Simon Withington,
3
@TenementFunster, dla tego samego kodu (bez wywołań zwolnienia), ARC będzie trzymać obiekt nie dłużej niż kod inny niż ARC. W rzeczywistości często wyda go wcześniej, niż byś to zrobił. Istnieje niewielka liczba rzeczy, które są nieco wolniejsze, ale tak bardzo przyspieszą typowe wzorce, że przyćmiewa wpływ na wydajność. W przypadku wielu typowych wzorców (na przykład zachowanie obiektu, który został zwrócony z automatycznym wydaniem), dosłownie nie można napisać tego ręcznie tak szybko, jak ARC zrobi to automatycznie.
Rob Napier,
1
Jeśli chodzi o wyrzucanie elementów bezużytecznych, zobacz moją odpowiedź na to podobne pytanie: Jaka jest różnica między automatycznym zliczaniem odwołań w celu C a wyrzucaniem elementów bezużytecznych?
Brad Larson

Odpowiedzi:

147

Nie ma wady. Użyj tego. Zrób to dzisiaj. Jest szybszy niż twój stary kod. Jest bezpieczniejszy niż twój stary kod. To jest łatwiejsze niż twój stary kod. To nie jest odśmiecanie. Nie ma narzutu czasu wykonania GC. Kompilator wstawia i zwalnia we wszystkich miejscach, które i tak powinieneś mieć. Ale jest mądrzejszy od ciebie i może zoptymalizować te, które nie są w rzeczywistości potrzebne (tak jak może rozwinąć pętle, wyeliminować zmienne tymczasowe, funkcje wbudowane itp.)

OK, teraz opowiem o małych wadach:

  • Jeśli jesteś wieloletnim programistą ObjC, będziesz drgać przez około tydzień, gdy zobaczysz kod ARC. Bardzo szybko przezwyciężysz to.

  • Istnieją pewne (bardzo) małe komplikacje w łączeniu się z kodem Core Foundation. Jest nieco więcej komplikacji w radzeniu sobie z wszystkim, co traktuje idjako void*. Rzeczy takie jak tablice C idmogą wymagać trochę więcej myślenia, aby wykonać je poprawnie. Fantazyjna obsługa ObjC va_argsmoże również powodować problemy. Większość rzeczy związanych z matematyką na wskaźniku ObjC jest trudniejsza. W każdym razie nie powinieneś mieć tego dużo.

  • Nie można umieścić idw sposób struct. Jest to dość rzadkie, ale czasami służy do pakowania danych.

  • Jeśli nie zastosowałeś prawidłowego nazewnictwa KVC i zmieszasz kod ARC i inny niż ARC, będziesz mieć problemy z pamięcią. ARC używa nazewnictwa KVC do podejmowania decyzji dotyczących zarządzania pamięcią. Jeśli to cały kod ARC, to nie ma to znaczenia, ponieważ zrobi to tak samo „źle” po obu stronach. Ale jeśli jest to mieszane ARC / inne niż ARC, oznacza to niezgodność.

  • ARC spowoduje wyciek pamięci podczas zgłaszania wyjątków ObjC. Wyjątek ObjC powinien być bardzo bliski zakończenia programu. Jeśli łapiesz znaczną liczbę wyjątków ObjC, używasz ich niepoprawnie. Można to naprawić za pomocą -fobjc-arc-exceptions, ale wiąże się to z karami omówionymi poniżej:

  • ARC nie spowoduje wycieku pamięci podczas zgłaszania wyjątków ObjC lub C ++ w kodzie ObjC ++, ale odbywa się to kosztem wydajności czasu i przestrzeni. To kolejny z długiej listy powodów, dla których warto zminimalizować użycie ObjC ++.

  • ARC w ogóle nie będzie działać na iPhoneOS 3 lub Mac OS X 10.5 lub starszym. (To wyklucza mnie z używania ARC w wielu projektach).

  • __weakwskaźniki nie działają poprawnie na iOS 4 lub Mac OS X 10.6, co jest wstydem, ale dość łatwe do obejścia. __weakwskazówki są świetne, ale nie są najważniejszym punktem sprzedaży ARC.

Dla ponad 95% kodu, ARC jest genialny i nie ma żadnego powodu, aby go unikać (pod warunkiem, że poradzisz sobie z ograniczeniami wersji systemu operacyjnego). W przypadku kodu innego niż ARC można przekazywać -fno-objc-arcplik po pliku. Niestety Xcode sprawia, że ​​jest to znacznie trudniejsze niż powinno to być w praktyce. Prawdopodobnie powinieneś przenieść kod inny niż ARC do oddzielnego xcodeproj, aby to uprościć.

Podsumowując, przełącz się na ARC tak szybko, jak to możliwe i nigdy nie oglądaj się za siebie.


EDYTOWAĆ

Widziałem kilka komentarzy w stylu „używanie ARC nie zastąpi znajomości zasad zarządzania pamięcią Cocoa”. Jest to w większości prawda, ale ważne jest, aby zrozumieć, dlaczego i dlaczego nie. Po pierwsze, jeśli cały twój kod używa ARC i naruszysz Trzy Magiczne Słowaw każdym miejscu nadal nie będziesz mieć problemów. Szokujące, ale proszę bardzo. ARC może zachować pewne rzeczy, których nie chciałeś zachować, ale uwolni je również, więc to nigdy nie będzie miało znaczenia. Gdybym dzisiaj prowadził nową klasę w kakao, prawdopodobnie spędziłbym nie więcej niż pięć minut na rzeczywistych zasadach zarządzania pamięcią i prawdopodobnie wspomniałbym tylko o regułach nazewnictwa zarządzania pamięcią, omawiając nazewnictwo KVC. Wierzę, że dzięki ARC mógłbyś zostać przyzwoitym początkującym programistą bez znajomości zasad zarządzania pamięcią.

Ale nie można było zostać przyzwoitym średniozaawansowanym programistą. Musisz znać zasady, aby poprawnie łączyć się z Core Foundation, a każdy średniozaawansowany programista musi w pewnym momencie poradzić sobie z CF. I musisz znać zasady dla mieszanego kodu ARC / MRC. I musisz znać zasady, kiedy zaczynasz bawić się void*wskazówkami id(które nadal musisz poprawnie wykonać KVO). A bloki ... cóż, zarządzanie pamięcią blokową jest po prostu dziwne.

Chodzi mi więc o to, że podstawowe zarządzanie pamięcią jest nadal ważne, ale tam, gdzie spędzałem dużo czasu na określaniu i powtarzaniu reguł dla nowych programistów, dzięki ARC staje się to bardziej zaawansowanym tematem. Wolałbym, aby nowi programiści myśleli w kategoriach grafów obiektowych, zamiast wypełniać ich głowy wywołaniami do objc_retain().

Rob Napier
źródło
3
Jedną rzeczą, na którą należy bardzo uważać (również w trybie innym niż ARC, ale bardziej w ARC, ponieważ jest teraz tak niewidoczny), jest zachowanie cykli. Moja rada jest następująca: 1) jeśli zauważysz, że przechowujesz blok objc jako zmienną instancji, przyjrzyj mu się uważnie, aby zobaczyć, czy może przechwycić obiekt, do którego należy, nawet pośrednio. 2) Właściwie zaprojektuj swój wykres obiektu, zamiast po prostu na to pozwolić. Państwo musi wiedzieć, co jest właścicielem co jeśli chcesz napisać dobry kod. 3) Użyj heapshotów: friday.com/bbum/2010/10/17/ ...
Catfish_Man
1
@Catfish_Man Wszystkie dobre strony. Pętle zatrzymujące zawsze były problemem. Nowa rada Apple jest dokładnie taka, jak mówisz w punkcie 2. Musimy raczej pomyśleć o grafach obiektowych niż o ich zachowaniu i zwolnieniu. # 1 to poważny problem z blokami i jednym z kilku powodów, dla których uważam bloki za mieszane błogosławieństwo, do którego należy podchodzić z ostrożnością.
Rob Napier,
2
Jest jedna poważna wada, o której nie wspomniano: kompatybilność krzyżowa. Dla nas, odważnych i głupich dusz, które stawiają czoła pustkowiom znanym jako programowanie wieloplatformowe, ARC po prostu nie wchodzi w grę, przynajmniej dopóki GNU nie rozszerzy ich środowiska wykonawczego ObjC i funkcji kompilatora (mówią, że więcej jest w drodze).
Królik
2
Możesz używać ARC z wyjątkiem tego, że musisz obsługiwać urządzenia iOS 3.x. BTW, upewnij się, że używasz Xcode do wykonania przejścia (Edycja> Refaktoryzacja> Konwertuj na ARC celu-C). Podczas tego procesu Xcode przeprowadziłby wiele weryfikacji, aby upewnić się, że kod będzie działał i wykryć wszelkie kody, które naruszają te wytyczne projektowe.
ZhangChn
1
Doskonała… odpowiedź punktowa. to setna ode mnie. Gratulacje za sto lat;)
Ajay Sharma
20

Lepsze, bardziej techniczne odpowiedzi niż moje, ale oto idzie:

  • ARC! = Czyszczenie pamięci. Nie ma kary za wykonanie, jest to wykonywane w czasie kompilacji.
  • ARC również! = Po prostu automatyczne zwalnianie wszystkiego, jak sugerujesz w swoim komentarzu. Przeczytaj dokumentację
  • To niesamowite, gdy zdajesz sobie sprawę, ile ręcznego zarządzania odniesienia Ci zostali robi
  • Użyj tego!
  • Jedna wada - utrzymywanie starego, niełukowego kodu nagle staje się bardzo uciążliwe.
jrturton
źródło
Tak, dlatego do tej pory go nie używałem - nie jestem pewien, czy byłbym w stanie przejść przez naszą znaczną ilość wcześniej istniejącego kodu, aby go przekonwertować ... Jednak na pewno wypróbuję go w następnym projekcie. Dzięki za odpowiedź :)
Simon Withington,
Nie chodzi o to, że utrzymanie starego kodu staje się trudniejsze, ale o to, że zmieniły się twoje oczekiwania. Więc nie jest sprawiedliwe obwinianie ARC za ułatwianie życia. Xcode ułatwia konwersję starego kodu do ARC, gdy jesteś gotowy, ale oczywiście nie możesz go używać, jeśli nadal potrzebujesz obsługi starszych wersji iOS.
Caleb,
1
@Caleb Nie winiłem ARC, to po prostu jedyny minus, jaki do tej pory widziałem - rozpieszcza mnie w przestrzeni jednego projektu.
jrturton,
Tak; Nie wymieniłem tego jako problemu, ale istnieje mały problem związany z wyjściem z praktyki zarządzania pamięcią, gdy musisz przełączać się między bazami kodu. Niektóre z moich projektów działają na 10.4, więc nadal wykonuję dużo pracy w Objective-C 1.0 (więc nie ma @synthesize, nie mówiąc już o ARC). Ale całkiem dobrze przyzwyczaisz się do przełączania trybów.
Rob Napier,
@jrturton Powinienem był wyjaśnić, że napisałem to z korzyścią dla OP i przyszłych czytelników, którzy mogą nie wiedzieć, czym zajmuje się ARC. Wiem dokładnie, co masz na myśli, ale nie chciałem, aby ktokolwiek wyciągnął błędny wniosek, że mieszanie kodu ARC i innego niż ARC stwarza problem.
Caleb,
16

Jakie korzyści może przynieść ARC do projektu?

Zaletą jest znaczny stopień ochrony przed typowymi błędami w zarządzaniu pamięcią. Wycieki spowodowane niepowodzeniem zwolnienia obiektu i awarie spowodowane brakiem zachowania lub przedwczesnym zwolnieniem obiektu powinny zostać znacznie zmniejszone. Nadal musisz zrozumieć model pamięci zliczanej referencji, aby móc sklasyfikować odwołania jako silne lub słabe, uniknąć cykli zachowywania i tak dalej.

Ile naprawdę „kosztuje” wywóz śmieci?

W iOS nie ma wyrzucania elementów bezużytecznych. ARC jest podobny do GC pod tym względem, że nie musisz ręcznie zachowywać ani zwalniać obiektów. W przeciwieństwie do GC, nie ma odśmiecacza. Model utrzymania / wydania nadal obowiązuje, po prostu kompilator wstawia odpowiednie wywołania zarządzania pamięcią do twojego kodu w czasie kompilacji.

Czy korzystałeś z ARC, a jeśli tak, to w jaki sposób je znalazłeś?

To trochę niepokojące, jeśli jesteś przyzwyczajony do liczenia odniesień, ale to tylko kwestia przyzwyczajenia się do tego i nauczenia się zaufania, że ​​kompilator naprawdę zrobi to, co trzeba. Wydaje się, że jest to kontynuacja zmiany właściwości wprowadzonej wraz z Objective-C 2.0, która była kolejnym dużym krokiem w kierunku uproszczenia zarządzania pamięcią. Bez ręcznego zarządzania pamięcią kod staje się trochę krótszy i łatwiejszy do odczytania.

Jedynym problemem z ARC jest to, że nie jest obsługiwany w starszych wersjach iOS, więc musisz wziąć to pod uwagę, zanim zdecydujesz się go zaadaptować.

Caleb
źródło
1
Jest lepsza odpowiedź, o której mówiłem!
jrturton,
1
Tak, świetna odpowiedź. Więc czy naprawdę nie ma żadnej wady dla ARC poza koniecznością nauczenia się zaufania, że ​​to działa? W takim razie wydaje się to zbyt piękne, aby mogło być prawdziwe?
Simon Withington,
4

Myślę, że ARC to świetny pomysł. W porównaniu do GC możesz mieć ciasto i też je zjeść. Uważam, że MRC narzuca nieocenioną „dyscyplinę” w zarządzaniu pamięcią, z której każdy skorzystałby. Ale zgadzam się również, że prawdziwym problemem, o którym należy wiedzieć, jest własność obiektu i wykresy obiektów (jak wielu wskazywało), a nie niskopoziomowe liczniki odwołań jako takie.

Podsumowując: ARC NIE jest darmową przepustką do bezmyślnego myślenia o pamięci; jest to narzędzie pomagające ludziom unikać powtarzających się zadań, które powodują stres i są podatne na błędy, dlatego lepiej delegowane na maszynę (w tym przypadku kompilator).

To powiedziawszy, osobiście jestem trochę rzemieślnikiem i jeszcze nie dokonałem przejścia. Właśnie zacząłem używać Git ...

AKTUALIZACJA: Więc zmigrowałem całą moją grę, w tym bibliotekę gl i jak dotąd żadnych problemów (z wyjątkiem asystenta migracji w Xcode 4.2). Jeśli zaczynasz nowy projekt, zrób to.

Nicolas Miari
źródło
2

Użyłem go w kilku (co prawda małych) projektach i mam tylko dobre doświadczenia, zarówno pod względem wydajności, jak i niezawodności.

Jedną drobną uwagą jest to, że musisz nauczyć się robić: s i nie: s słabych odwołań, aby nie powodować żadnych pętli referencyjnych, jeśli sam kodujesz swój interfejs użytkownika, projektant zazwyczaj wykonuje dobrą robotę automatycznie, jeśli użyjesz go do swojego GUI.

Joachim Isaksson
źródło
2

Jedynym minusem, z jakim się spotkałem, jest to, że używasz biblioteki z wieloma funkcjami i danymi CoreFoundation. W MRC nie trzeba było martwić się o używanie CFStringRefzamiast NSString*. W ARC musisz określić, w jaki sposób te dwa elementy wchodzą w interakcję (podstawowy most? Zwolnić obiekt CoreFoundation i przenieść go do ARC? Utworzyć obiekt Cocoa jako obiekt zachowany na +1 CoreFoundation?). Ponadto w systemie OS X jest dostępny tylko na 64- kod bitowy (chociaż mam nagłówek, który działa wokół tego…).

MaddTheSane
źródło