# Symbols:
# Address Size File Name
0x100006510 0x0000001C [809] __GLOBAL__sub_I_MemoryFile.mm
0x10000652C 0x00000024 [396] __GLOBAL__sub_I_LabelImage.cpp
0x100006550 0x00000090 [399] __GLOBAL__sub_I_FBAssociationManager.mm
近来我们一直在做ipa包大小的缩减,在删除了无用图片,缩减项目中图片的体积,取得了较大的效果。但是成果背后的问题也接踵而至,删除完了图片,压缩完了图片大小之后我们应该怎么来减小ipa包大小呢?从哪里去减小,减小什么,怎么减小呢?
带着这样的问题,我们先来了解下ipa包的构成: ipa包主要由三大部分构成: ipa包解压之后 主要由三部分构成: 1.可执行文件。 2.Asset.car文件。asset文件夹中图片的压缩文件 3.其他:_CodeSignature文件夹,签名信息; 我们之前做的事情主要是缩小2与3中的内容,那么接下来我们需要缩小的是1的内容了。 既然想要缩减可执行文件的大小,那么可执行文件是这啥这是个什么东西? 使用file命令查看 这个可执行文件; 这是个Mach-O文件类型,里面包含了两个架构:armv7&arm64.
Mach-O? Mach-O格式是个啥?是怎么组成的? 我们知道Windows下的文件都是PE文件,同样在OS X和iOS中可执行文件是Mach-O格式的。Mach-O包含三个基本区域: ?头部(header structure)。 ?加载命令(load command)。 ?段(segment)。可以拥有多个段(segment),每个段可以拥有零个或多个区域(section)。每一个段(segment)都拥有一段虚拟地址映射到进程的地址空间。 ?链接信息。一个完整的用户级Mach-o文件的末端是链接信息。其中包含了动态加载器用来链接可执行文件或者依赖库所需使用的符号表,字符串表等等。 头部信息和加载命令都是用来描述应用程序类型的,链接信息则是如符号表之类的,所以Mach-O中最重要的部分是这些segment。
segment是啥呢?来看看普通的编译过程吧: 基本的编译过程分为四个步骤: 预处理(Pre-process):把宏替换,删除注释,展开头文件,产生 .i 文件。 编译(Compliling):使用预处理后的单词构建词法树,生成语法树输出AST (Abstract Syntax Tree),将AST转化成更低级的中间码(LLVM IR),优化中间代码生成输出汇编代码,把之前的 .i 文件转换成汇编语言,产生 .s文件。 汇编(Asembly):把汇编语言文件转换为机器码文件,产生 .o 文件。 链接(Link):对.o文件中的对于其他的库的引用的地方进行引用,生成最后的可执行文件(同时也包括多个 .o 文件进行 link)
那么我们知道了Mach-O文件是一堆segment组成的,而可执行程序是由 .o文件link而成的,那么这些.o文件应该能反应segement的大小,也能反应可执行程序的大小。
好,我们现在的目标变成了去看.o文件的大小,那么现在让我们来看看linkMap。 linkMap打开是个啥: Mach-O是编译完成的二进制文件,LinkMap是中间产生的如符号表类的文件,这个LinkMap里展示了整个可执行文件的全貌,列出了编译后的每一个.o目标文件的信息(包括静态链接库.a里的),以及每一个目标文件的代码段,数据段存储详情。
linkMap的结构: linkMap文件一般有三个部分:1.在LinkMap里首先列出来的是目标文件列表:前面中括号里的是这个文件的编号,后面会用到,像项目里引用到静态链接库里的目标文件都会在这里列出来。如编号[2]的B.o和编号[5]的A.o
2.接着是一个段表,描述各个段在最后编译成的可执行文件中的偏移位置及大小,包括了代码段(**TEXT,保存程序代码段编译后的机器码)和数据段(DATA,保存变量值)。 首列是数据在文件的偏移位置,第二列是这一段占用大小,第三列是段类型,代码段和数据段,第四列是段名称。 这里可以清楚看到各种类型的数据在最终可执行文件里占的比例,例如text表示编译后的程序执行语句,**data表示已初始化的全局变量和局部静态变量,__cstring表示代码里的字符串常量,等等。
每一行的数据都紧跟在上一行后面,如第二行symbol_stub的地址0x100006BD8就是第一行text的地址0×100006A68加上大小0x00000170,整个可执行文件大致数据分布就是这样。 3.接着就是按上表顺序,列出具体的按每个文件列出每个对应字段的位置和占用空间。同样首列是数据在文件的偏移地址,第二列是占用大小,第三列是所属文件序号,对应上述Object files列表,最后是名字 例如第51行代表了文件序号为5(反查上面就是A)的function1A方法占用了4byte大小。5000)
linkMap的用法: 根据上面的介绍,我们可以把所有file相同的size加起来,就可以得到该文件的大小了,根据文件的前缀名,就可以得到项目中各个独立模块的大小了。还可以对两个迭代得到的linkmap文件分析结果进行比较就可以得出,这个迭代相比上个迭代新增了多少文件,减少了多少文件,哪些文件比较大需要减小等等信息。
linkMap文件的获取方法:
在xcode中设置编译选项:XCode -> Project -> Build Settings -> 搜map -> 把Write Link Map File选项设为yes,并在Path to Link Map File中指定好linkMap的存储位置。 编译完成之后,即可在存储位置获得linkMap文件。
我这边写了个脚本用于分析LinkMap信息,并生成Excel。 地址 如有问题 欢迎咨询。
参考资料: build过程:www.objccn.io/issue-6-1/编译过程:segmentfault.com/a/119000000… clang & LLVM: kb.cnblogs.com/page/114879… .tbd文件:www.tuicool.com/articles/Jv… www.cocoachina.com/ios/2016050…
作者:拾雪
链接:https://juejin.cn/post/6844903524157898766
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。