Jak znaleźć przyczynę błędu „podwójnego braku” malloc?

80

Programuję aplikację w Objective-C i otrzymuję ten błąd:

MyApp (2121,0xb0185000) malloc: *** błąd dla obiektu 0x1068310: podwójne wolne
*** ustaw punkt przerwania w malloc_error_break do debugowania

Dzieje się tak, gdy wypuszczam NSAutoreleasePool i nie mogę dowiedzieć się, który obiekt dwukrotnie wypuszczam.

Jak ustawić jego punkt przerwania?

Czy istnieje sposób, aby dowiedzieć się, co to jest ten „obiekt 0x1068310”?

gonso
źródło
4
możesz również oznaczyć ten post iPhone'em, aby przyciągnąć więcej osób
Benny Wong
4
Usunięto tag „iphone” na rzecz innych, bardziej odpowiednich tagów.
Quinn Taylor
3
Nie mogę sobie wyobrazić, dlaczego w tym pytaniu na iPhone'a brakuje tagu iPhone'a. Musi być więcej osób obserwujących „iPhone'a” niż niektóre inne tagi, takie jak „autorelease”. Jeśli chcesz znaleźć „autorelease”, szukaj go, nie podążaj za znacznikiem. Więc włożyłem „iPhone'a” z powrotem.
Nosredna
6
Usunąłem znacznik „iphone”, ponieważ nic w tym pytaniu nie jest specyficzne dla iPhone'a. Jedynym łączem jest to, że występuje w aplikacji na iPhone'a, ale dokładnie ten sam błąd może wystąpić w dowolnej aplikacji C lub Objective-C. Nie spodziewam się, że ludzie śledzący iPhone'a byliby tym zainteresowani - raczej byliby to ludzie, którzy szukają takich rzeczy jak „double free” lub „malloc_error_break”, a jeśli wrzucą „iPhone”, to i tak się pojawi . Nie kłóćmy się o tagi, ale zastanówmy się, że być może osoby, które udzielą odpowiedzi, mogą wiedzieć, gdzie najlepiej pasuje pytanie.
Quinn Taylor,
3
To pytanie dotyczy przynajmniej kakao. Jeśli tag iPhone'a obraża, co powiesz na tag kakaowy? Oczywisty zamiar dotyczy Objective-C na Cocoa w XCode. Nie Objective-C w systemie Windows, Linux lub poza kontekstem XCode.
runako

Odpowiedzi:

38

Dowiesz się, czym jest obiekt, gdy włamiesz się do debugera. Wystarczy spojrzeć na stos wywołań, a znajdziesz miejsce, w którym go uwolnisz. To powie ci, który to jest obiekt.

Najłatwiejszym sposobem ustawienia punktu przerwania jest:

  1. Idź do Run -> Show -> Breakpoints ( ALT- Command- B)
  2. Przewiń na dół listy i dodaj symbol malloc_error_break
Frank Krueger
źródło
1
Próbowałem tego, ale otrzymałem: nie można rozłączyć malloc_error_break… co to znaczy?
Gonso,
3
Brak pomocy dla autorelease podwójnie za darmo. On potrzebuje Zombies
Rog,
58
@gonso - Ciekawe, że jeśli to nie zadziałało, dlaczego zaakceptowałeś to jako odpowiedź?
Quinn Taylor
8
W Xcode 4.3.2 punkty przerwania można znaleźć w View → Navigators → Show Breakpoints Navigator lub ⌘6 (Cmd-6)
Andreas Ley
46

Gdy obiekt jest „podwójnie zwalniany”, najczęstszą przyczyną jest to, że (niepotrzebnie) zwalniasz obiekt, który jest automatycznie zwalniany, a później jest on automatycznie zwalniany, gdy zawierająca pula autowywolnienia zostanie opróżniona.

Odkryłem, że najlepszym sposobem na śledzenie dodatkowego wydania jest użycie zmiennej środowiskowej NSZombieEnabled dla pliku wykonywalnego, którego dotyczy problem, w Xcode. Aby dowiedzieć się, jak z niego korzystać, odwiedź tę stronę wiki CocoaDev . (Oprócz tej strony firma Apple udokumentowała kilka niewiarygodnie mało znanych, ale przydatnych wskazówek dotyczących debugowania kodu w Xcode, z których niektóre pozwoliły zaoszczędzić mój bekon więcej niż kilka razy. Proponuję zapoznać się z tą uwagą techniczną na developer.apple.com - link przeskakuje do sekcji dotyczącej frameworka Cocoa's Foundation).

Edycja: Często możesz wyśledzić obraźliwy obiekt w debugerze Xcode, ale często jest to znacznie łatwiejsze, jeśli używasz Instruments do pomocy. W Xcode wybierz Uruchom → Uruchom z Performance Tool → Object Alocations i powinieneś być w stanie prześledzić problematyczny obiekt z powrotem do miejsca, w którym został utworzony. (Działa to najlepiej, jeśli masz włączone zombie, jak omówiono powyżej). Uwaga: Snow Leopard dodaje narzędzie Zombie do instrumentów, dostępne również z menu Uruchom. Samo może być warte 29 $! ;-)

Jest tu również powiązane pytanie SO .

Quinn Taylor
źródło
1
Strona wiki
CocoaDev, do której
Use the Way Back Machine: web.archive.org/web/20120325135712/http://www.cocoadev.com/…
Quinn Taylor,
12

Chcę tylko dodać moje doświadczenie jako dodatek do odpowiedzi Quinna Taylora.

W jednej z moich aplikacji muszę analizować i zapisywać dane w podstawowych obiektach danych, a później wyświetlać te obiekty w widokach. W rzeczywistości aplikacja działa dobrze i wcale się nie zawiesza, dopóki nie próbowałem wykonać testu warunków skrajnych, aby wielokrotnie nawigować tam iz powrotem, próbowałem otworzyć wiele widoków tak szybko, jak to możliwe. Aplikacja ulega awarii z powyższym komunikatem.

Wypróbowałem wszystkie metody, które zasugerował Quinn w swojej odpowiedzi i nadal nie udało mi się ustalić, gdzie jest dokładna przyczyna.

Ustawiłem NSZombieEnabled = YES i NSStackLogging = YES, uruchomiłem powłokę poleceń malloc_history, aby dowiedzieć się, dlaczego, ale nadal nie mam szczęścia. Zawsze wskazuje miejsce, w którym zapisuję dane w podstawowych obiektach danych, w rzeczywistości sprawdzałem tysiące razy ponad zwolnione obiekty, nic dziwnego.

Uruchomienie w instrumentach z różnymi narzędziami (alokacje, wycieki itp.) Nadal nie pomogło. Włącz Guard Malloc nadal nic nie ma.

Ostateczna ratunek: próbowałem wrócić do widoków, w których obiekty zostały zabrane z danych podstawowych i wysłałem wiadomość o zachowaniu do wszystkich tych obiektów oraz odnotowałem te zmiany. To rozwiązało problem !!!

Więc dowiedziałem się, że nie udało mi się jednego zachować, to jest dokładnie przyczyna. Chcę tylko podzielić się moim doświadczeniem, aby mieć kolejną ratunek dla swojej aplikacji.

Hoang Pham
źródło
9

Otwórz konsolę debugera, naciskając Cmd + Shift + R. Tam, wpisz

break malloc_error_break

aby ustawić punkt przerwania na początku malloc_error_breakfunkcji.

Jeśli chcesz dowiedzieć się, jaki obiekt znajduje się pod adresem 0x1068310, możesz wpisać w konsoli debugera:

print-object 0x1068310

Oczywiście musisz to zrobić, gdy obiekt wciąż żyje - jeśli obiekt został już uwolniony do czasu, gdy to zrobisz, to nie zadziała.

Adam Rosenfield
źródło
To jest autorelease, on potrzebuje Zombie.
Rog
1
W końcu wywołałem „podejrzaną” metodę poza AutoreleasePoll. Zabawna myśl, że nadal otrzymałem ostrzeżenie, ale nie osiągnięto żadnego punktu zwrotnego. Po prostu wykomentowałem bloki, aż znalazłem linię. Automatycznie zwalniałem ciąg, który został utworzony za pomocą stringWithFormat (bez alokacji lub kopiowania). Dziękuję wszystkim za wskazówki! Gonso
gonso
W przypadku tego rodzaju błędu włamanie na malloc_error_break nigdy nie pomogło w znalezieniu problemu - zawsze wymagało włączenia zombie.
Quinn Taylor,
Zobacz tutaj, aby uzyskać instrukcje dotyczące ustawiania punktu przerwania dla malloc_error_break w XCode 4: stackoverflow.com/questions/6969407/ ...
benvolioT
1
@Zammbi: Spróbuj użyć poaliasu lub jego odpowiednika expr -o. W latach, które minęły od napisania tej odpowiedzi, silnik debugowania używany przez Xcode został zmieniony z GDB na LLDB, a LLDB ma inny zestaw poleceń.
Adam Rosenfield,
4

U mnie problem został rozwiązany przez

(gdb) call (void)_CFAutoreleasePoolPrintPools()

zaraz po wypadku. Adres na górze stosu był adresem sprawcy. Wrzuciłem a retaini voila.

Adres podany w komunikacie dziennika nigdzie mnie nie zaprowadził. Nigdy nie pojawił się w żadnym z różnych instrumenetów. Najwyraźniej wskazówka do niektórych danych wewnętrznych, które zostały już uwolnione.

c-alfa
źródło
4

Dodanie symbolicznego punktu przerwania w Xcode 4

Tylko aktualizacja, aby było to istotne dla Xcode 4 ...

Z podręcznika użytkownika Xcode 4 :

Aby dodać symboliczny punkt przerwania. . .

  1. W lewym dolnym rogu nawigatora punktów przerwania kliknij przycisk Dodaj.
  2. Wybierz opcję Dodaj symboliczny punkt przerwania.
  3. Wprowadź nazwę symbolu w polu Symbol.
  4. Kliknij Gotowe.
Stary McStopher
źródło
2

Sprawdź swoje zajęcia i spójrz pod metodę dealloc. Upewnij się, że zadzwonisz[super dealloc].

Miałem dokładnie ten sam problem i dowiedziałem się, że dzwonię [self dealloc]. Po prostu nie zwracam uwagi.

Wes Duff
źródło
2

Proszę znaleźć poniższe kroki, aby znaleźć obiekt, który jest wolny i zawiesić aplikację.

1) Kliknij „ Nawigator punktów przerwania ”.
2) Następnie kliknij przycisk „ + ” znajdujący się poniżej.
3) Dodaj „ Symboliczny punkt przerwania… ” z listy.
4) Dodaj słowo kluczowe „ malloc_error_break ” do opcji „ Symbol ”.

Możesz też odnieść się do poniższej prezentacji GIF.

Reprezentacja GIF

Ramkrishna Sharma
źródło
1

Zwykle jest to spowodowane przez jakiegoś inspektora, na przykład safari lub podgląd safari. Zapoznaj się z postem lub postem i pytaniem .

Usunięcie zaznaczenia opcji AutoMatically Show Web .... spowoduje usunięcie tego problemu.

Uwaga, po prostu zamknij safari lub podgląd safari nie usunie tego problemu. Musisz też odznaczyć zarówno podgląd safari, jak i safari.

Jeśli to nie pomoże, zapoznaj się z tą odpowiedzią lub postem, aby go zdebugować.

odznacz automatycznie sprawdzaj w podglądzie safari

LF00
źródło
0

W Xcode kliknij lewą stronę numeru linii, aby ustawić punkt przerwania. Następnie możesz go uruchomić, wykonując „Buduj i debuguj”.

Zaleca się, aby nie tworzyć obiektów, autoreleaseponieważ pamięć jest towarem w telefonie iPhone. Apple zaleca bezpośrednie dzwonienie release.

Benny Wong
źródło
0

Aby znaleźć tego rodzaju problemy z pamięcią i wskaźnikami w ogóle, chcesz uruchomić kod w oparciu o moduł sprawdzania błędów pamięci w czasie wykonywania, taki jak Valgrind . To powinno być w stanie wskazać wiele rzeczy, które twój kod robi źle, poza tymi, które powodują awarię.

Valgrind może pracować na OSX (chociaż mówi, że jest „nieobsługiwany, niekompletny i zawiera błędy”), a po drobnym włamaniu ktoś zmusił go do pracy na plikach wykonywalnych iPhone SDK .

Jeszcze lepiej możesz wypróbować Instruments, który jest częścią XCode. Jest to poradnik do uruchamiania go tutaj .

Jared Oberhaus
źródło
1
instrumenty to droga do zrobienia; użyj instrumentu alokacji obiektu i włącz zombie. (lub po prostu użyj szablonu Zombies). Valgrind to rozwiązanie ostatniej szansy. Jest strasznie powolny i często po prostu nie działa.
bbum
0

Jeśli malloc_error_breaknie pomaga ...

Najlepszym sposobem rozwiązania tego błędu jest uruchomienie instrumentów przy NSZombieswłączonych. Instruments oznaczy Cię flagą, gdy Zombie otrzyma wiadomość i możesz prześledzić bezpośrednio z powrotem do linii kodu.

Wymagany Snow Leopard, co za ratownik!

iOSDevSF
źródło