iOS 编译后,引入的一些第3方库都会被编译到可执行文件内,可执行文件相当于windows电脑下载 exe文件。
下面将介绍这个可执行文件的构成,分析一下那些库占用空间大,方法如下:
1、开启Write Link Map File
XCode -> Project -> Build Settings -> 搜索map关键词 -> 把Write Link Map File选项设为Yes,并指定好linkMap的存储位置(默认有路径,txt文件)
image.png
2、编译之后,找到对应的txt文件
上述的Path to Link Map File位于:(以arm64命令集为例)
~/Library/Developer/Xcode/DerivedData/项目名称-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/ArchiveIntermediates/项目名/IntermediateBuildFilesPath/项目名称.build/Debug-iphoneos/项目名称.build/项目名称-LinkMap-normal-arm64.txt
这个LinkMap里展示了全部可执行文件的全貌,列出了编译后的每个.o文件的信息(包括静态链接库.a里的),以及每一个目标文件的代码段,数据段存储详情。
以TestApp项目为例,在LinkMap里首先列出来的是目标文件列表:
# Path: /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Products/Debug-iphoneos/TestApp.app/TestApp
# Arch: arm64
# Object files:
[ 0] linker synthesized
[ 1] dtrace
[ 2] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/AppDelegate+NIM.o
[ 3] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/AppDelegate+XCLConstantsConfig.o
[ 4] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/AppDelegate.o
[ 5] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/XCLLaunchScreenViewController.o
[ 6] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/AppDelegate+Share.o
[ 7] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/AppDelegate+XCLRouter.o
[ 8] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/AppDelegate+EaseMob.o
[ 9] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/AppDelegate+SensorsAnalytics.o
[ 10] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/AppDelegate+XCLRootViewController.o
[ 11] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/main.o
[ 12] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/AppDelegate+PadConfig.o
[ 13] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Intermediates.noindex/TestApp.build/Debug-iphoneos/TestApp.build/Objects-normal/arm64/AppDelegate+XCLDataBase.o
[ 14] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Products/Debug-iphoneos/AFNetworking/libAFNetworking.a(AFAutoPurgingImageCache.o)
[ 15] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Products/Debug-iphoneos/AFNetworking/libAFNetworking.a(AFHTTPSessionManager.o)
[ 16] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Products/Debug-iphoneos/AFNetworking/libAFNetworking.a(AFImageDownloader.o)
[ 17] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Products/Debug-iphoneos/AFNetworking/libAFNetworking.a(AFNetworkActivityIndicatorManager.o)
[ 18] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Products/Debug-iphoneos/AFNetworking/libAFNetworking.a(AFNetworking-dummy.o)
[ 19] /Users/lmy/Library/Developer/Xcode/DerivedData/TestApp-aodmtzoayqjaqicjfnybtopdiamz/Build/Products/Debug-iphoneos/AFNetworking/libAFNetworking.a(AFNetworkReachabilityManager.o)
...
中括号里的是这个文件的编号,后面会用到,像项目里引用到静态链接库libAFNetworking.a里的目标文件都会在这里列出来。
接着是一个段表,描述各个段在最后编译成的可执行文件中的偏移位置及大小,包括了代码段(__TEXT,保存程序代码段编译后的机器码)和数据段(__DATA,保存变量值)
# Sections:
# Address Size Segment Section
0x100004800 0x01FD335C __TEXT __text
0x101FD7B5C 0x00004404 __TEXT __stubs
0x101FDBF60 0x00003A74 __TEXT __stub_helper
0x101FDF9D4 0x000B8150 __TEXT __gcc_except_tab
0x102097B30 0x00138DF9 __TEXT __cstring
0x1021D0929 0x000B096C __TEXT __objc_methname
0x102281296 0x0000DED0 __TEXT __ustring
0x10228F166 0x00011591 __TEXT __objc_classname
0x1022A06F7 0x000185FF __TEXT __objc_methtype
0x1022B8D00 0x000A3618 __TEXT __const
0x10235C318 0x0000037B __TEXT __dof_RACSignal
0x10235C693 0x000002E8 __TEXT __dof_RACCompou
0x10235C97C 0x00036F78 __TEXT __unwind_info
0x1023938F8 0x000006E4 __TEXT __eh_frame
0x102394000 0x00001688 __DATA __got
0x102395688 0x00002D58 __DATA __la_symbol_ptr
0x1023983E0 0x000004B8 __DATA __mod_init_func
0x1023988A0 0x000CC8A8 __DATA __const
0x102465148 0x000674E0 __DATA __cfstring
0x1024CC628 0x00004D98 __DATA __objc_classlist
0x1024D13C0 0x000000A8 __DATA __objc_nlclslist
0x1024D1468 0x00000850 __DATA __objc_catlist
0x1024D1CB8 0x00000030 __DATA __objc_nlcatlist
0x1024D1CE8 0x000008D8 __DATA __objc_protolist
0x1024D25C0 0x00000008 __DATA __objc_imageinfo
0x1024D25C8 0x00244FD0 __DATA __objc_const
0x102717598 0x00027030 __DATA __objc_selrefs
0x10273E5C8 0x00000120 __DATA __objc_protorefs
0x10273E6E8 0x00004A10 __DATA __objc_classrefs
0x1027430F8 0x000030F0 __DATA __objc_superrefs
0x1027461E8 0x0000DD10 __DATA __objc_ivar
0x102753EF8 0x00030840 __DATA __objc_data
0x102784740 0x000CD4A0 __DATA __data
0x102851BE0 0x00114168 __DATA __bss
0x102966000 0x000DC020 __DATA __common
首列是数据在文件的偏移位置,
第二列是这一段占用大小,
第三列是段类型,代码段和数据段,
第四列是段名称。
每一行的数据都紧跟在上一行后面,如第二行__symbol_stub的地址0x00275FD0就是第一行__text的地址0x00002740加上大小0x00273890,整个可执行文件大致数据分布就是这样。
这里可以清楚看到各种类型的数据在最终可执行文件里占的比例,例如__text表示编译后的程序执行语句,__data表示已初始化的全局变量和局部静态变量,__bss表示未初始化的全局变量和局部静态变量,__cstring表示代码里的字符串常量,等等。
接着就是按上表顺序,列出具体的按每个文件列出每个对应字段的位置和占用空间
# Sections:
# Address Size Segment Section
0x100004800 0x01FD335C __TEXT __text
0x101FD7B5C 0x00004404 __TEXT __stubs
0x101FDBF60 0x00003A74 __TEXT __stub_helper
0x101FDF9D4 0x000B8150 __TEXT __gcc_except_tab
0x102097B30 0x00138DF9 __TEXT __cstring
0x1021D0929 0x000B096C __TEXT __objc_methname
0x102281296 0x0000DED0 __TEXT __ustring
0x10228F166 0x00011591 __TEXT __objc_classname
0x1022A06F7 0x000185FF __TEXT __objc_methtype
0x1022B8D00 0x000A3618 __TEXT __const
0x10235C318 0x0000037B __TEXT __dof_RACSignal
0x10235C693 0x000002E8 __TEXT __dof_RACCompou
0x10235C97C 0x00036F78 __TEXT __unwind_info
0x1023938F8 0x000006E4 __TEXT __eh_frame
0x102394000 0x00001688 __DATA __got
0x102395688 0x00002D58 __DATA __la_symbol_ptr
0x1023983E0 0x000004B8 __DATA __mod_init_func
0x1023988A0 0x000CC8A8 __DATA __const
0x102465148 0x000674E0 __DATA __cfstring
0x1024CC628 0x00004D98 __DATA __objc_classlist
0x1024D13C0 0x000000A8 __DATA __objc_nlclslist
0x1024D1468 0x00000850 __DATA __objc_catlist
0x1024D1CB8 0x00000030 __DATA __objc_nlcatlist
0x1024D1CE8 0x000008D8 __DATA __objc_protolist
0x1024D25C0 0x00000008 __DATA __objc_imageinfo
0x1024D25C8 0x00244FD0 __DATA __objc_const
0x102717598 0x00027030 __DATA __objc_selrefs
0x10273E5C8 0x00000120 __DATA __objc_protorefs
0x10273E6E8 0x00004A10 __DATA __objc_classrefs
0x1027430F8 0x000030F0 __DATA __objc_superrefs
0x1027461E8 0x0000DD10 __DATA __objc_ivar
0x102753EF8 0x00030840 __DATA __objc_data
0x102784740 0x000CD4A0 __DATA __data
0x102851BE0 0x00114168 __DATA __bss
0x102966000 0x000DC020 __DATA __common
同样首列是数据在文件的偏移地址,第二列是占用大小,第三列是所属文件序号,对应上述Object files列表,最后是名字。
例如第二行代表了文件序号为2(反查上面就是TKPFileInfo.o)的parseWithDictionary方法占用了1000byte大小。
这个文件可以让你了解整个APP编译后的情况,也许从中可以发现一些异常,还可以用这个文件计算静态链接库在项目里占的大小,有时候我们在项目里链了很多第三方库,导致APP体积变大很多,我们想确切知道每个库占用了多大空间,可以给我们优化提供方向。LinkMap里有了每个目标文件每个方法每个数据的占用大小数据,所以只要写个脚本,就可以统计出每个.o最后的大小,属于一个.a静态链接库的.o加起来,就是这个库在APP里占用的空间大小。
文件分析工具:# LinkMap
LinkMap解析工具:检查每个类占用大小
一个大型的项目,只是代码段就有可能超过100M,算上armv7和arm64架构,就会超过200M。 这时候检查到底是哪个类、哪个第三方库占用了太多空间,就显得尤为重要。
这个工具是专为用来分析项目的LinkMap文件,得出每个类或者库所占用的空间大小(代码段+数据段),方便开发者快速定位需要优化的类或静态库。
使用说明
1、打开LinkMap.xcodeproj,并运行,就可以看到工具界面
image.png
2、点击“选择文件”按钮,选择LinkMap文件(如何生成LinkMap详见下方的:如何获得LinkMap文件)
3、点击“开始”按钮,就可以看到每个类/静态库所占用的空间大小
image.png
4、点击“输出文件”,可以将结果输出到文本文档中
网友评论