Ответ 1
Как правило:
- с сообщением о сбое, вы получите трассировку стека
- с spindumps, вы получаете несколько следов стека в течение определенного периода времени вместе.
Есть два случая, когда вы можете изучить spindump:
- бесконечный цикл, возможно, повторяющий одну и ту же функцию снова и снова
- тупиковый.
Первый случай можно увидеть из spindump многими вызовами одной и той же функции снова и снова. Хорошей вещью для использования в таких ситуациях является Activity Monitor - выберите образец висячего процесса, и вы сможете просмотреть его несколькими полезными способами, спрятать несущественные фреймы и т.д.
Второй случай можно просматривать разными потоками, ожидающими блокировки одновременно.
Вот небольшой пример:
+ 2663 start (in MyApp) + 52 [0x100001bb4]
+ 2663 main (in MyApp) + 39 [0x100001be7] main.m:65
+ 2663 NSApplicationMain (in AppKit) + 869 [0x7fff8ea27cb6]
+ 2663 -[NSApplication run] (in AppKit) + 517 [0x7fff8ea83283]
+ 2663 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] (in AppKit) + 128 [0x7fff8ea8bed2]
+ 2663 _DPSNextEvent (in AppKit) + 685 [0x7fff8ea8c613]
+ 2663 BlockUntilNextEventMatchingListInMode (in HIToolbox) + 62 [0x7fff8dd53cd3]
+ 2663 ReceiveNextEventCommon (in HIToolbox) + 356 [0x7fff8dd53e42]
+ 2663 RunCurrentEventLoopInMode (in HIToolbox) + 209 [0x7fff8dd540a4]
+ 2663 CFRunLoopRunSpecific (in CoreFoundation) + 290 [0x7fff95dec6b2]
+ 2557 __CFRunLoopRun (in CoreFoundation) + 1078 [0x7fff95decee6]
+ ! 2556 __CFRunLoopServiceMachPort (in CoreFoundation) + 195 [0x7fff95de7803]
+ ! : 2556 mach_msg (in libsystem_kernel.dylib) + 70 [0x7fff93630c42]
+ ! : 2556 mach_msg_trap (in libsystem_kernel.dylib) + 10 [0x7fff93631686]
+ ! 1 __CFRunLoopServiceMachPort (in CoreFoundation) + 199 [0x7fff95de7807]
+ 97 __CFRunLoopRun (in CoreFoundation) + 728 [0x7fff95decd88]
+ ! 97 __CFRunLoopDoObservers (in CoreFoundation) + 369 [0x7fff95e11921]
+ ! 97 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ (in CoreFoundation) + 23 [0x7fff95e119b7]
+ ! 97 __83-[NSWindow _postWindowNeedsDisplayOrLayoutOrUpdateConstraintsUnlessPostingDisabled]_block_invoke_01208 (in AppKit) + 46 [0x7fff8f05a971]
+ ! 90 _handleWindowNeedsDisplayOrLayoutOrUpdateConstraints (in AppKit) + 738 [0x7fff8ea8f2ac]
+ ! : 89 -[NSView displayIfNeeded] (in AppKit) + 1830 [0x7fff8ea8fd73]
То, что это говорит мне, это то, что MyApp прошел через main и т.д. и, наконец, попал в функцию CFRunLoopRunSpecific
, затем __CFRunLoopRun
- оттуда (2557) он назвал __CFRunLoopServiceMachPort
, который вызвал mach_msg
и попал в ловушку в mach_msg_trap
(вызов syscall) - когда он вернулся, трассировка стека вернулась в CFRunLoopRunSpecific
, где был вызван __CFRunLoopRun
, который затем вызывает __CFRunLoopDoObservers
и т.д.
Обратите внимание, что это не spindump любого висячего процесса - вы можете проследить этот процесс любым запущенным процессом и посмотреть, какие функции были вызваны во время этого примера. Тем не менее, бесконечный цикл будет повторять вызовы для некоторой функции снова и снова - снова и снова будет одно и то же дерево вызовов. Конечно, это может означать простое для цикла, но это то, где вы можете исследовать, если цикл for не почему-то бесконечен. К сожалению, эти отвалы спина обычно довольно длинные, в зависимости от того, какую функцию вы вызываете, поэтому может потребоваться некоторое время для изучения
Знак + в начале строки просто указывает начало строки - строки без знака + указывают начало нового потока.! и: знаки делают линию, так что вам легче видеть последующие вызовы, т.е. какие вызовы находятся на одном уровне. Далее, | символ также можно использовать.
Цифры означают, сколько времени приложение потрачено на этот конкретный вызов - они находятся в количестве образцов. Сэмплирование работает, что выборочное приложение приостанавливается каждые несколько миллисекунд, и кадр стека исследуется для каждого потока. Если приложение все еще находится в одной и той же функции, функция получает +1.