概念
符号表
符号表是内存地址与函数名、文件名、行号的映射表。符号表元素如下所示:
<起始地址> <结束地址> <函数> [<文件名:行号>]
Debug Symbol 调试符号
借助符号调试程序可以将原始符号表转换成可读性较强的符号表,主要是方便开发人员获取调试信息
还原前:
1 | Thread 0 Crashed: |
还原后:
1 | Thread 0 Crashed: |
DWARF
一种支持源代码级别调试的调试文件格式
DWARF是平台独立的且适用于任何处理器任何操作系统
dSYM
iOS平台中,dSYM文件是指具有调试信息的目标文件,文件名通常为:xxx.app.dSYM
为了避免进行 Strip 操作后调试符号的丢失,你可以使用dwarf-with-dsym选项。
DWARF with dSYM 选项在标准的DWARF之外执行一个额外的步骤:创建一个单独的MyApp.app.dSYM文件,这个文件包含你的程序的所有调试符号(这个文件其实是一个包,可以通过右键->显示包内容进行查看)。
事实上,DWARF with dSYM选项允许你对你进行单步调试而不管可执行程序是否被剥离了调试信息(stripped)。
这是可能的,这是因为gdb将会在你的程序的目录下查找.dSYM文件。它不需要知道对象文件(object files)的名字或者路径。如果你不除去调试符号 (strip debugging symbols),你可以使用.o或者.dSYM文件来调试。
DWARF - Object files and linked products will use DWARF as the debug information format. [dwarf]
DWARF with dSYM File - Object files and linked products will use DWARF as the debug information format, and Xcode will also produce a dSYM file containing the debug information from the individual object files (except that a dSYM file is not needed and will not be created for static library or object file products). [dwarf-with-dsym]
静态库无法产生 dsym
编译选项
Generate Debug Symbols
是否产生调试符号
当Generate Debug Symbols设置为YES时,编译产生的.o文件会大一些,当然最终生成的可执行文件也大一些(亲测如此)
当Generate Debug Symbols设置为NO的时候,在Xcode中设置的断点不会中断。但是在程序中打印 [NSThread callStackSymbols],依然可以看到类名和方法名
在程序崩溃时,也可以得到带有类名和方法名的函数调用栈
1 | 9 QQLiveInternational 0x00000001069c2515 -[QVNUICustomView layoutSubviews] + 3253 |
结论:Debug/Release 均打开
Debug Information Level
调试符号携带的信息等级
Debug Information Level
默认值为 Compiler default
,另一个选项是 Line tables only
Generate Debug Symbols
= YES 的前提下,如果选择 Line tables only
,调试信息带有函数名、文件名和行号,但是不包含其他数据(比如局部变量和函数参数)。所以断点可以工作,但是无法在 lldb 中查看局部变量的值(亲测如此)
Deployment Postprocessing
该选项是所有 Strip 选项的总开关
Strip,也就是把生成的 .o 文件中剥离特定的符号(symbols)
Strip Linked Product
- 如果
Deployment Postprocessing
不打开,该选项没有作用 - 如果该选项生效,app 构建的过程多了两步
- 在app构建的开始,会生成一些.hmap辅助文件
- 在app构建的末尾,会执行Strip操作
- 如果该选项生效,断点不会中断,在程序中打印
[NSThread callStackSymbols]
也无法看到类名和方法名,程序崩溃时无法看到类名和方法名
Strip Style
Strip Linked Product
打开时该选项才生效(待验证)
剥离符号的程度依次是All Symbols
> Non-Global Symbols
> Debugging Symbols
All Symbols
:剥离所有符号表和重定向信息,适用于最后生成 .app 的工程Non-Global Symbols
:剥离非全局的符号(包括调试符号),保留外部符号,适用于 bundle 和 frameworkDebugging Symbols
:剥离调试符号,保留局部符号和全局符号,都适用
Strip Linked Product
= YES 时,如果把 Strip Style
从 All Symbols
改为 Debugging Symbols
,则程序崩溃时就可以看到类名和方法名
注意如果构建的是一个静态库,则不可以 strip all,因为剥离了所有符号的静态库是无法被正常链接的(亲测编译失败)
Link Time Optimization
优点:
- 将一些函数內联化
- 去除了一些无用代码
- 对程序有全局的优化作用
缺点:
- 降低编译链接速度,只建议在打正式包时开启
- 降低 link map 可读性(多出了很多数字开头的“类”)
我是如何把 600M 的库减少到 30M
1 | Deployment Postprocessing = 1 |
不过这样会导致 crash 时无法查看堆栈信息
参考文章
注意
- 是对 Framrwork 的 Target 进行设置,而不是用于打包的 Target
Generate Debug Symbols
= NO,Deployment Postprocessing
= NO时,体积仍然很大(猜测:strip 不止剥离了 debug symbols,还剥离了其他内容,比如符号表)