提问人:ramnik 提问时间:9/22/2023 更新时间:9/26/2023 访问量:33
如何使用 Thread.callStackSymbols 分析从另一个线程调用的父方法的 ID?
How can I parse the ID of a parent method that calls from another thread by using Thread.callStackSymbols?
问:
我正在尝试实现一个小型分析解决方案,以自动化方式跟踪整个代码库中的调用。
不幸的是,我对低级操作系统的东西一无所知,我什至不知道如何谷歌这些东西。因此,我不清楚以下几点:
- 堆栈跟踪中的列指的是什么?
- 什么是内存加载地址?
- 什么是退货地址?
我确实发现堆栈跟踪中索引 2 处的列是调用方法的唯一标识符,索引 3 处的列是其父方法的唯一标识符。这样,我就可以在同一线程中跟踪子方法和父方法。(有时这似乎被重复使用,但这没关系,因为那时我已经跟踪了跟踪。0x1234
0x1234
- 当父方法从另一个线程调用时,如何从子方法中跟踪父方法?
- 如何在堆栈跟踪中查看子方法通过闭包完成?
在 Xcode 中调试时,我在 Xcode 侧面板中看到此信息,所以它一定是某个!
除此之外,我迷失了。请帮忙?
我还在此处附加了此示例的代码:
import Foundation
struct Dog {
func bark() {
print("CallStackSymbols for '\(#function)':")
print("\t\(Thread.callStackSymbols.joined(separator: "\n\t"))")
DispatchQueue.global(qos: .userInitiated).async {
barkInBackground()
}
}
func barkInBackground() {
print("CallStackSymbols for '\(#function)':")
print("\t\(Thread.callStackSymbols.joined(separator: "\n\t"))")
}
}
let dog = Dog()
dog.bark()
sleep(1000)
答:
经过大量研究,我自己找到了问题的答案。
--
我将省略以下问题的答案,因为根据新信息,它们已经变得无关紧要,而且我觉得没有足够的能力令人满意地回答它们:
- 堆栈跟踪中的列指的是什么?
- 什么是内存加载地址?
- 什么是退货地址?
--
重构问题 #1:“如何在 iOS 中获取 NSThread 的”父“线程?
你不能。没有父线程这样的东西。线程是一个 独立实体,即使线程可以与其他线程通信 线程,但不涉及层次结构。(来源)
--
重构问题 #2:“如何跨多个线程跟踪方法的逻辑跟踪?
当将新任务分配给后台队列时,您必须将 id 传递到 的闭包中(这可能会在后台创建一个新线程)。DispatchQueue
(这里不可能进行干净的方法切换,因为您必须更改原始实现而不是向其添加某些内容。
下面是一个有效的示例代码 (=> 希望其跟踪包含多个线程的客户必须使用自定义包装器(例如扩展方法),因为 iOS 不会公开任何接口来以自动方式执行此操作。
let traceId = UUID().uuidString
DispatchQueue.global(qos: .userInitiated).async {
Tracker.trackMethod(self, parentId: traceId)
barkInBackground()
}
libdispatch 是 Darwin 系统的一部分,用于处理队列和运行块等。这也是调试器查询此历史“谁在何时调度了什么”信息的代理。但是,已安装的调度运行时库:/usr/lib/system/libdispatch.dylib 不会收集任何此类信息。这是因为这样做(甚至真的添加功能来这样做)会减慢执行速度,增加内存使用量,并且 libdispatch 不需要它来完成它的实际工作。Dispatch 是系统中非常关键的性能部分,因此库的正常版本无法承担超出必要范围的工作。
取而代之的是,有一个 libdispatch 的“内省”版本,当您启用“队列调试”功能时,Xcode 会加载该版本而不是普通版本。该版本的 libdispatch 确实收集了这些信息,并提供了一个 API 来访问它,lldb 使用它来生成这些“历史线程”。你可以看到你确实在使用变体库:如果在 Xcode 中停止时,你运行 lldb 命令:
(lldb) image list libdispatch.dylib
[ 0] 6C6BE4E9-B201-3B02-8E69-33DF61FF3A44 0x0000000102ad8000 /usr/lib/system/introspection/libdispatch.dylib
这是正在使用的 libdispatch 的内省版本。
但是,在 Darwin 系统上正常运行的应用程序不应加载此库,因此不会收集有关队列和调度的历史信息,也不会提供查询此信息的 API。因此,如果您想自己跟踪它,则必须按照所示手动进行。
评论