2013-01-10 12 views
6

Preambuła; To NIE jest ogólne pytanie "Mam gigantyczną aplikację z przeciekiem". Jest to specyficzny problem dotyczący automatycznego liczenia odwołań, który nie działa poprawnie w prawie banalnej aplikacji demo, z pełnym kodem źródłowym lub subtelnym generowaniem kodu lub kompilatorem lub błędem w Instrumentach. (TLDR: Oh, w rzeczywistości dziwny mały wyścig)Przeciek pamięci fantomowej z ARC w XCode 4.5, gdzie dealloc jest zdecydowanie nazywany lub kwestią Instrumentów?

Jestem zdezorientowany faktem, że lista "Przydziałów instrumentów" pokazuje przeciek instancji, a mimo to mam instancję tej klasy, tylko jedną, i ARC powoduje wywołanie metody dealloc i wiem, że jest ona wywoływana, ponieważ istnieje komunikat NSLog, który jest drukowany po zakończeniu dealloc, a mimo to nadal jest wyświetlany na liście przecieków w Instruments.

Wartość zatrzymana nigdy nie przekracza 1. Nie jest ona zatrzymywana przez nikogo i jest dealloc'd, a mimo to wygląda na to, że jest to "przeciek", ponieważ jest ona aktywna w przypadku przecieków Instrumentu.

Jak to możliwe?

Nadal uczę się Objective-C z ARC, więc myślę, że muszę popełnić wspólny błąd początkującego. Oto tylko mój startowych i dealloc mojego obiektu:

- (id) initWithMessage:(NSString*)messageForUser 
{ 
    self = [super init]; 
    if (self) 
    { 
     _message = messageForUser; 
     NSLog(@"from constructor: %@",_message); 
    } 
    return self; 

} 

- (void)dealloc { 
    NSLog(@"Goodbye cruel world. One WPMyObject signing off."); 
    // [message release]; // ARC forbiddeth thee! Begone release. 
    _message = nil; 

    // [super dealloc]; // ARC forbiddeth explicit super dealloc 
} 

Wystarczy, aby zobaczyć, czy mogę, próbowałem zadzwonić [super dealloc] w metodzie dealloc i ARC bloki z błędem, co jest dobre, bo to zrobi To dla ciebie. Jednak kiedy piszę własną metodę init, nie blokuje mnie.

Po uruchomieniu programu przy użyciu "Uruchom" w XCode, otrzymuję komunikat "żegnaj okrutny świat" NSLog, jak miałem nadzieję, że zrobię, gdy uruchomi się dealloc, ale otrzymuję również dowody, że instancja nadal istnieje koniec przebiegu, gdy używana jest analiza Instrumentów wykorzystująca szablon wycieków pamięci:

Jeśli uruchomię bez kodu tworzenia instancji poniżej, otrzymam tylko kilka standardowych wycieków malloc biblioteki, ale jeśli dodaję ten kod, wszystkie przecieki występują:

WPMyObject * myObject = [[WPMyObject alloc] initWithMessage: @"Hello World!\n" ]; 

Oto co widzę, i myślę, że rozumiem, mówiąc mi, że jedyny przypadek WPMyObject za przecieka:

enter image description here

pełny kod źródłowy, który jest dość trywialne (mały Mac OS X za pomocą wiersza poleceń aplikacji Objective-C i Foundation/Foundation.h) jest BitBucket. Kliknij przycisk this link, aby wyświetlić kod źródłowy w przeglądarce.

Jednostka main.m biegnie pojedynczy tworzenie instancji obiektu testy, wewnątrz instrukcji @autoreleasepool {...} kontekstu:

enter image description here

Jeśli chcesz zobaczyć kod całkowicie trywialny na własnym komputerze, chwyć go tak :

hg clone https://bitbucket.org/wpostma/objectivecplaymac 

Aktualizacja: można rozwiązać ten „przeciek” (który może być błędem w Instruments, lub dzyń/llvm kompilator błąd, a nie „prawdziwy przeciek”) poprzez dodanie tego wiersza kodu tuż przed }, który kończy pulę autorelease:

NSLog(@"Reached end of autorelease pool"); 

Tak. Dodaj wiadomość do dziennika. "Wyciek" odchodzi.Jest to XCode 4.5.2 (4G2008a) na Mac OS X 10.7.5, zawierający Instruments w wersji 4.5 (kompilacja 4523).

Update2: To naprawdę prosty, wieloprocesowy wyścig. Poniższy kod wydaje się być sensownym kawałkiem hackery opartym na debugowaniu. Jeśli byłby bardziej wyraźny sposób powiedzenia "poczekaj, aż Instruments zrobi się ze mną, a następnie wyjdź z main()", może to być dobra funkcja przyszłościowa, inżynierowie Apple. Makro PROFILER_SYNC ("MESSAGE"), które rozwija się do niczego w trybie zwolnienia, ale w kompilacjach debugujących wysyła "MESSAGE" do profilera .... To może być bardzo przydatne.

int main(int argc, const char * argv[]) 
{ 
    // This creates and cleans up an auto-release pool context. 
    @autoreleasepool { 

     foo(); // Microscopic amounts of debug code you want profiler to analyze go here. 

#ifdef DEBUG 
     usleep(10000); // race condition prevention in debug builds, so Instruments can finish up. 
#endif 

    } 
#ifdef DEBUG 
    usleep(10000); // race condition prevention in debug builds, so Instruments can finish up. 
#endif 

    return 0; 
} 

Odpowiedz

3

Brzmi mniej jak wyciek, a bardziej przypomina wyścig. Wyścig pomiędzy pisaniem NSLog i kończeniem wykonywania programu. Lub bardziej prawdopodobny problem z buforowaniem, gdy dane wyjściowe nie zostaną usunięte, dopóki nie zostanie osiągnięty określony próg.

Spróbuj wstawić sleep(100); po klamrze zamykającej w puli autorelease. Lub spróbuj dodać kilka dodatkowych tekstu do wiadomości dziennika w dealloc.

Jeśli to nie "naprawi", następnie pokaż demontaż i zobacz, jakie zmiany zachodzą między dwiema wersjami kodu.


Powód, dla którego tak się dzieje: Zarówno Instruments, jak i NSLog() są skutecznie buforowane ze względu na wydajność. Są one przeznaczone do użycia w stosunkowo długim procesie, który prawie zawsze ma główną pętlę zdarzeń lub wywołanie do dispatch_main().

Robi się to, aby spróbować minimalnie wpłynąć na wydajność docelowej aplikacji, ale może prowadzić do dziwactwa w mikro-punktach odniesienia, w których proces jest wyjątkowo krótki.

Jeśli masz krótki przypadek testowy w krótkim okresie, polecam zamknięcie main() z [[NSRunLoop currentLoop] run];. To będzie działać wiecznie i da ci realistyczny czas na działanie Instrumentów i/lub debuggera.

+0

Zasadniczo, wyścigowy stan między wrotami do oglądania sterty Instrumentów, a głównym wątkiem mojego programu? Ponieważ to są jedyne dwa wątki/procesy, jakie mogę sobie wyobrazić, ponieważ nie zrobiłem żadnych dodatkowych wątków użytkownika ... Dziwne jest to, że NSLog to naprawia, ale wywołanie CFShow (CFStr ("coś")) nie powoduje, co oznacza, że ​​jeśli jest to wyścig, NSLog jest dużo wolniejszy niż CFShow. :-) –

+0

sleep (100) (100 sekund) może być trochę przesadą. :-) Zmieniono na uśpienie na 100 ms, w dwóch miejscach, w których, jak sądzę, Instruments może trochę czasu dogonić akcję. Dwojakie i dodaj jedenastu jeden, jeśli chcesz, drodzy przyszli czytelnicy. –

Powiązane problemy