我正在尝试实现一个小型的分析解决方案,以自动化的方式跟踪整个代码库中的调用。
不幸的是,我对底层操作系统的东西一无所知,我甚至不知道如何谷歌这些东西。因此,以下几点对我来说是不清楚的:
1.堆栈跟踪中的列指的是什么?
1.什么是内存加载地址?
1.什么是回邮地址?
我确实发现,在堆栈跟踪中索引2处的0x1234
列是调用方法的唯一标识符,索引3处的列是其父方法的唯一标识符。这样我就可以跟踪同一个线程中的子方法和父方法。(有时这个0x1234
似乎被重用,但这没关系,因为在那一点上我已经跟踪了跟踪。)
1.如何在子方法中跟踪父方法,当它被另一个线程调用时?
1.如何在stacktrace中看到子方法通过闭包完成?
当在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)
2条答案
按热度按时间ergxz8rk1#
libdispatch是达尔文系统中处理队列和运行块等的一部分。这也是调试器查询”谁在何时调度了什么“历史信息的代理。然而,安装的调度运行时库:/usr/lib/system/libdispatch.dylib并不收集这些信息。(或者实际上甚至添加了这样做的启示)会减慢执行速度,增加内存使用,并且libdispatch并不需要它来完成它的真实的工作。dispatch是系统的一个非常关键的性能部分,因此库的普通版本无法承受做不必要的工作。
相反,有一个“内省”版本的libdispatch,当你启用“队列调度”功能时,Xcode会加载它而不是普通版本。这个版本的libdispatch确实收集了这些信息,并提供了一个API来访问它,lldb使用它来生成这些“历史线程”。你可以看到你确实在使用变体库:如果在Xcode中停止时,你运行lldb命令:
这就是所使用的libdispatch的内省版本。
但是在达尔文系统上正常运行的应用程序不应该加载这个库,因此不会收集有关队列和分派的历史信息,也不会提供查询此信息的API。因此,如果您想自己跟踪它,您必须手动完成,如您所示。
hec6srdp2#
经过大量的研究,我自己找到了问题的答案。
1.* 堆栈跟踪中的列指的是什么?*
1.* 什么是内存加载地址 *
1.* 什么是回邮地址 *
重新定义问题#1:“How to get a "parent" thread for NSThread in iOS?“
你不能。没有父线程这样的东西。线程是一个独立的实体,即使一个线程可以与其他线程通信,但没有涉及层次结构。(Source)
重新定义问题#2:“如何跨多线程跟踪方法的逻辑跟踪?”
当一个新的任务被赋予一个后台队列(这可能会在后台创建一个新的线程)时,你必须向
DispatchQueue
的闭包传递一个id。(这里不可能进行干净的方法混合,因为您必须更改原始的实现,而不是添加一些东西。
下面是一个工作的示例代码(=>希望跟踪包含多个线程的客户,必须使用自定义 Package 器(例如扩展方法)因为iOS没有公开任何接口以自动方式完成此操作)。