2012-01-07 10 views
17

Tak więc zdarzało się dość często w Crashlytics, zarówno na iPadzie, jak i iPadzie 2, z systemem iOS 5. Wygląda na to, że spowodowało to ostrzeżenie o pamięci, ale ślad stosu nie działa. t odniesienia któregokolwiek z mojego kodu aplikacji, zaledwie ramy iOS:UIViewController purgeMemoryForReason: Awaria na iOS 5

0 libobjc.A.dylib objc_msgSend + 15 
1 UIKit   -[UIViewController purgeMemoryForReason:] + 64 
2 Foundation  __57-[NSNotificationCenter addObserver: selector: name: object:]_block_invoke_0 + 18 
3 CoreFoundation  ___CFXNotificationPost_block_invoke_0 + 70 
4 CoreFoundation  _CFXNotificationPost + 1406 
5 Foundation  -[NSNotificationCenter postNotificationName: object: userInfo:] + 66 
6 Foundation  -[NSNotificationCenter postNotificationName: object:] + 30 
7 UIKit   -[UIApplication _performMemoryWarning] + 80 
8 UIKit   -[UIApplication _receivedMemoryNotification] + 174 
9 libdispatch.dylib _dispatch_source_invoke + 516 
10 libdispatch.dylib _dispatch_queue_invoke + 50 
11 libdispatch.dylib _dispatch_main_queue_callback_4CF + 156 
12 CoreFoundation  __CFRunLoopRun + 1268 
13 CoreFoundation  CFRunLoopRunSpecific + 300 
14 CoreFoundation  CFRunLoopRunInMode + 104 
15 GraphicsServices GSEventRunModal + 156 
16 UIKit   UIApplicationMain + 1090 
17 500px iOS  main.m line 12 

mam google wysokie i niskie, ale nie można znaleźć żadnych rozwiązań do tego. Wygląda na to, że jest to spowodowane nadmiernym zwolnieniem instancji UIViewController, ale używam ARC, więc nie widzę, jak to możliwe.

Brakuje mi możliwości podejścia do tego problemu. Nie mogę nawet stwierdzić, która przyczyna problemu powoduje podklasa UIViewController. Próbowałem odtworzyć problem w symulatorze i na urządzeniu, ale nie mogę znaleźć przyczyny. Czy ktoś widział coś takiego lub ma sugestie dotyczące podejścia do powielania problemu?

+2

Interesujące. Zwykle następnym krokiem na stosie byłoby wywołanie unloadViewIfReloadable dla tego kontrolera viewController. Teraz, gdy widzimy teraz awarię, oznacza to, że ta metoda nie została jeszcze osiągnięta lub że mamy już za sobą ten krok. W drugim przypadku sprawdź implementacje metody viewDidUnload. To byłby następny krok, który bym rozważył. Jako standardową rekomendację włącz zombie i wyzwolić ostrzeżenie o pamięci na symulatorze. – Till

+0

Dam ci ten strzał i wrócę do ciebie. Dzięki! –

Odpowiedz

17

Myślę, że rozwiązałem problem. Myślałem o tym, a problem nie polega na rozładowywaniu widoku UIViewController, jest to wysyłanie powiadomienia o ostrzeżeniu o małej ilości pamięci. W moim kodzie jest kilka wystąpień, które wywołują [[NSNotificationCenter defaultCenter] removeObserver:self]. Jest to w porządku w metodzie dealloc, ale były dwa przykłady tego w metodach viewDidUnload.

Zauważyłem to, gdy mój punkt przerwania w didReceiveMemory jednego z kontrolerów UIViewController nie został trafiony. Kod w viewDidUnload również wyrejestrował self z innych powiadomień systemowych, jak szczegółowo here.

Nie zamierzam oznaczyć tego jako zaakceptowanej odpowiedzi, dopóki nie sprawdzę, czy awarie kończą się z nową aktualizacją.

AKTUALIZACJA: Sprawdziłem w Crashlytics, że problem został rozwiązany!

+2

Tak, złota zasada notyfikacji przestrzegająca: usuń obserwatorów tylko z tych zgłoszeń, na które się zarejestrowałeś. Czytałem o tym jakiś czas temu, ale nigdy nie doświadczyłem tak wyraźnych konsekwencji. Cieszę się, że naprawiłeś swój problem. – iHunter

+0

@AshFurrow usuwa siebie z tych powiadomień na viewDidUnload _only_, jeśli rejestrujesz się w widoku viewDidLoad. – Till

+0

@ Problem jest, UIViewController wydaje się rejestrować dla powiadomień o inicjalizacji, że jestem wyrejestrowywanie dla w viewDidUnload. Zmieniono mój removeObserver: aby usunąćObserver: name: object: tak, żebym tylko * * wyrejestrowywał określone powiadomienia. –

8

zauważyłem dokładnie ten sam ślad stosu w wypadkach zgłoszonych przez HockeyApp dla urządzeń z systemem iOS 5.

I never called[[NSNotificationCenter defaultCenter] removeObserver:self] wyjątkiem wewnątrz dealloc, więc to nie może być przyczyną wypadku.

Oto, w jaki sposób udało mi się odtworzyć awarię: od MasterViewController Pcham DetailViewController, a następnie pop nim, dotykając przycisku Wstecz. Na koniec uruchamiam ostrzeżenie o pamięci i następuje awaria (tylko w systemie iOS 5).

Okazuje się, że instancja DetailViewController nie zostanie zwolniony po wpadliśmy z powodu cyklu zachować podczas korzystania SVPullToRefresh:

@implementation DetailViewController 

- (void) viewDidLoad 
{ 
    [super viewDidLoad]; 

    [self.scrollView addPullToRefreshWithActionHandler:^{ 
     [self refresh]; 
    }]; 
} 

@end 

Od DetailViewController nie zostanie zwolniony to jeszcze zarejestrowany dla pamięci powiadomień ostrzegawczych i to, co dzieje:

frame #0: 0x0004d61b MyApp`-[DetailViewController dealloc](self=0x089a5150, _cmd=0x024d2738) + 27 at DetailViewController.m:103 
frame #1: 0x0227ae3d libobjc.A.dylib`_objc_rootRelease + 47 
frame #2: 0x0227ae00 libobjc.A.dylib`objc_release + 48 
frame #3: 0x0227c047 libobjc.A.dylib`objc_storeStrong + 39 
frame #4: 0x0004e44c MyApp`__destroy_helper_block_ + 44 at DetailViewController.m:157 
frame #5: 0x029b555d libsystem_sim_blocks.dylib`_Block_release + 166 
frame #6: 0x0227ae00 libobjc.A.dylib`objc_release + 48 
frame #7: 0x0227c047 libobjc.A.dylib`objc_storeStrong + 39 
frame #8: 0x00084c8d MyApp`-[SVPullToRefreshView .cxx_destruct](self=0x08bf3af0, _cmd=0x00000001) + 525 at UIScrollView+SVPullToRefresh.m:121 
frame #9: 0x0226630d libobjc.A.dylib`object_cxxDestructFromClass + 104 
frame #10: 0x02270fde libobjc.A.dylib`objc_destructInstance + 38 
frame #11: 0x02271015 libobjc.A.dylib`object_dispose + 20 
frame #12: 0x0247a9a1 CoreFoundation`-[NSObject dealloc] + 97 
frame #13: 0x00a8cdc7 UIKit`-[UIView dealloc] + 748 
frame #14: 0x0227ae3d libobjc.A.dylib`_objc_rootRelease + 47 
frame #15: 0x00a90b73 UIKit`-[UIView(Hierarchy) removeFromSuperview] + 194 
frame #16: 0x00a8cc10 UIKit`-[UIView dealloc] + 309 
frame #17: 0x00a9d6ff UIKit`-[UIScrollView dealloc] + 405 
frame #18: 0x013ab36c Foundation`NSKVODeallocate + 105 
frame #19: 0x0227ae3d libobjc.A.dylib`_objc_rootRelease + 47 
frame #20: 0x00b21c12 UIKit`-[UIViewController setView:] + 447 
frame #21: 0x00b21885 UIKit`-[UIViewController unloadViewForced:] + 117 
frame #22: 0x00b2180b UIKit`-[UIViewController unloadViewIfReloadable] + 41 
frame #23: 0x00b256ff UIKit`-[UIViewController purgeMemoryForReason:] + 75 
frame #24: 0x00b2563b UIKit`-[UIViewController didReceiveMemoryWarning] + 41 
frame #25: 0x00b2560d UIKit`-[UIViewController _didReceiveMemoryWarning:] + 33 
frame #26: 0x0141ca29 Foundation`__57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 40 
frame #27: 0x02443855 CoreFoundation`___CFXNotificationPost_block_invoke_0 + 85 
frame #28: 0x02443778 CoreFoundation`_CFXNotificationPost + 1976 
frame #29: 0x0136119a Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 98 
frame #30: 0x0136db03 Foundation`-[NSNotificationCenter postNotificationName:object:] + 55 
frame #31: 0x00a64cf4 UIKit`-[UIApplication _performMemoryWarning] + 91 
frame #32: 0x00a64e00 UIKit`-[UIApplication _receivedMemoryNotification] + 180 
frame #33: 0x00a64f98 UIKit`__block_global_0 + 36 
frame #34: 0x029f1450 libdispatch.dylib`_dispatch_source_invoke + 719 
frame #35: 0x029edcc4 libdispatch.dylib`_dispatch_queue_invoke + 66 
frame #36: 0x029ee4cf libdispatch.dylib`_dispatch_main_queue_callback_4CF + 295 
frame #37: 0x023af803 CoreFoundation`__CFRunLoopRun + 2003 
frame #38: 0x023aed84 CoreFoundation`CFRunLoopRunSpecific + 212 
frame #39: 0x023aec9b CoreFoundation`CFRunLoopRunInMode + 123 
frame #40: 0x038d07d8 GraphicsServices`GSEventRunModal + 190 
frame #41: 0x038d088a GraphicsServices`GSEventRun + 103 
frame #42: 0x00a5a626 UIKit`UIApplicationMain + 1163 
frame #43: 0x00002b82 MyApp`main(argc=1, argv=0xbffff318) + 178 at main.m:15 

lub w języku angielskim: instancja SVPullToRefreshView jest uwalniany w wyniku widoku zwalnianego. Ponieważ instancja SVPullToRefreshView jest ostatnim obiektem przechowującym odwołanie do DetailViewController, zostaje zwolniona, a następnie przydzielona. Ale purgeMemoryForReason: nadal był robienie rzeczy (tj. Uzyskiwanie dostępu do zmiennych instancji) z just deallocated kontroler widoku, a więc awarii.

Po zdiagnozowaniu rozwiązanie było bardzo proste: po prostu unikaj cyklu zatrzymania.

@implementation DetailViewController 

- (void) viewDidLoad 
{ 
    [super viewDidLoad]; 

    __typeof__(self) __weak weakSelf = self; 
    [self.scrollView addPullToRefreshWithActionHandler:^{ 
     [weakSelf refresh]; 
    }]; 
} 

@end 
+0

Jednym z błędów jest purgeMemoryForReason nie zachowuje się samodzielnie, zanim wykona swoją pracę, a następnie zwolni się po zakończeniu. Innym jest to, że VC nie ma silnego związku z jego poglądami, opierając się na założonym porządku dla pomyślnego wyłomu w hierarchii widoku. –

Powiązane problemy