我有一系列针对需要分析的应用程序的 Spindump,但我不确定如何准确分析这些。我见过其他一些开发人员能够在精神上或通过软件快速解析这些问题,然后向我提供有关挂起的位置等的详细信息,我希望了解如何正确分析这些问题。
一个人去哪里正确地分析spindumps?
我有一系列针对需要分析的应用程序的 Spindump,但我不确定如何准确分析这些。我见过其他一些开发人员能够在精神上或通过软件快速解析这些问题,然后向我提供有关挂起的位置等的详细信息,我希望了解如何正确分析这些问题。
一个人去哪里正确地分析spindumps?
一般来说:
在两种情况下,您可能需要检查 spindump:
第一种情况可以从 spindump 中看到,通过多次调用相同的函数。在这种情况下使用的一个好东西是活动监视器——在那里对挂起的进程进行采样,您可以通过几种有用的方式查看它,隐藏不重要的帧等。
第二种情况可以通过不同线程同时等待锁来查看。
这是一个小例子:
+ 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
,堆栈跟踪返回到CFRunLoopRunSpecific
,在哪里__CFRunLoopRun
被调用,然后调用__CFRunLoopDoObservers
,等等。
请注意,这不是任何挂起进程的旋转转储 - 您可以通过这种方式对任何正在运行的进程进行采样,并查看在该示例期间调用了哪些函数。然而,无限循环将一遍又一遍地重复调用某个函数——一遍又一遍地存在相同的调用树。当然,这可能意味着一个简单的 for 循环,但如果 for 循环由于某种原因不是无限的,那么您可以在那里检查。不幸的是,这些自旋转储通常很长,具体取决于您调用的函数,因此可能需要一些时间来检查
行首的 + 符号仅表示一行的开始 - 没有 + 符号的行表示新线程的开始。这 !和 : 符号组成一条线,因此您更容易看到后续呼叫 - 即哪些呼叫处于同一级别。此外,| 也可以使用字符。
这些数字表示应用程序在该特定呼叫中花费了多长时间 - 它们是样本数量。采样工作每隔几毫秒暂停采样的应用程序,并检查每个线程的堆栈帧。如果应用程序仍在同一个函数中,则该函数将获得 +1。
我在 Mac 开发人员资源中搜索“spindump”时发现了这一点。我从未见过,但 ReportCrash(8) 手册页中提到的这个 TechNote 似乎向您展示了如何阅读崩溃日志:
https://developer.apple.com/library/mac/#technotes/tn2004/tn2123.html
ReportCrash(8) 提到了 Spindump(8),我很抱歉。 https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man8/ReportCrash.8.html
但显然这对你没有帮助。我也会把它留在这里。
希望这能以某种方式帮助某人。