iOS APP
編譯后,除了一些資源文件,剩下的就是一個可執行文件,有時候項目大了,引入的庫多了,可執行文件很大,想知道這個可執行文件的構成是怎樣,里面的內容都是些什么,哪些庫占用空間較高,可以用以下方法:
-
XCode開啟編譯選項Write Link Map File
XCode -> Project -> Build Settings -> 搜map -> 把Write Link Map File選項設為yes,并指定好linkMap的存儲位置
linkmap 編譯后,到編譯目錄里找到該txt文件,文件名和路徑就是上述的Path to Link Map File
位于~/Library/Developer/Xcode/DerivedData/XXX-eumsvrzbvgfofvbfsoqokmjprvuh/Build/Intermediates/XXX.build/Debug-iphoneos/XXX.build/
這個LinkMap
里展示了整個可執行文件的全貌,列出了編譯后的每一個.o目標文件的信息(包括靜態鏈接庫.a里的),以及每一個目標文件的代碼段,數據段存儲詳情。
1
以樂刻app
項目為例,在LinkMap
里首先列出來的是目標文件列表:
# Object files:
[ 0] linker synthesized
[ 1] dtrace
[ 2] /Users/Info/Library/Developer/Xcode/DerivedData/LeoaoApp-bbaahkhqznaaetaczyjxchtoaxvf/Build/Intermediates.noindex/LeoaoApp.build/Debug-iphoneos/LeoaoApp.build/Objects-normal/arm64/LKTestDebugManager.o
[ 3] /Users/Info/Library/Developer/Xcode/DerivedData/LeoaoApp-bbaahkhqznaaetaczyjxchtoaxvf/Build/Intermediates.noindex/LeoaoApp.build/Debug-iphoneos/LeoaoApp.build/Objects-normal/arm64/LKClubActivityCell.o
[ 4] /Users/Info/Library/Developer/Xcode/DerivedData/LeoaoApp-bbaahkhqznaaetaczyjxchtoaxvf/Build/Intermediates.noindex/LeoaoApp.build/Debug-iphoneos/LeoaoApp.build/Objects-normal/arm64/LKMineUserInfoView.o
[ 5] /Users/Info/Library/Developer/Xcode/DerivedData/LeoaoApp-bbaahkhqznaaetaczyjxchtoaxvf/Build/Intermediates.noindex/LeoaoApp.build/Debug-iphoneos/LeoaoApp.build/Objects-normal/arm64/LKCourseOnStoreModel.o
[ 6] /Users/Info/Library/Developer/Xcode/DerivedData/LeoaoApp-bbaahkhqznaaetaczyjxchtoaxvf/Build/Intermediates.noindex/LeoaoApp.build/Debug-iphoneos/LeoaoApp.build/Objects-normal/arm64/LKOpenDoorScanQRViewModel.o
[ 7] /Users/Info/Library/Developer/Xcode/DerivedData/LeoaoApp-bbaahkhqznaaetaczyjxchtoaxvf/Build/Intermediates.noindex/LeoaoApp.build/Debug-iphoneos/LeoaoApp.build/Objects-normal/arm64/LKClubActMemberListApiManager.o
[ 8] /Users/Info/Library/Developer/Xcode/DerivedData/LeoaoApp-bbaahkhqznaaetaczyjxchtoaxvf/Build/Intermediates.noindex/LeoaoApp.build/Debug-iphoneos/LeoaoApp.build/Objects-normal/arm64/LKHomeThemeInfoAPI.o
[ 9] /Users/Info/Library/Developer/Xcode/DerivedData/LeoaoApp-bbaahkhqznaaetaczyjxchtoaxvf/Build/Intermediates.noindex/LeoaoApp.build/Debug-iphoneos/LeoaoApp.build/Objects-normal/arm64/LKClubCoachWallController.o
[ 10] /Users/Info/Library/Developer/Xcode/DerivedData/LeoaoApp-bbaahkhqznaaetaczyjxchtoaxvf/Build/Intermediates.noindex/LeoaoApp.build/Debug-iphoneos/LeoaoApp.build/Objects-normal/arm64/LKMemberInfoModel.o
前面中括號里的是這個文件的編號,后面會用到,像項目里引用到靜態鏈接庫的目標文件都會在這里列出來。
2
接著是一個段表,描述各個段在最后編譯成的可執行文件中的偏移位置及大小,包括了代碼段(__TEXT,保存程序代碼段編譯后的機器碼)和數據段(__DATA,保存變量值)
# Sections:
# Address Size Segment Section
0x100006C88 0x024F7ABC __TEXT __text
0x1024FE744 0x0000579C __TEXT __stubs
0x102503EE0 0x00004FE0 __TEXT __stub_helper
0x102508EC0 0x00181F0C __TEXT __cstring
0x10268ADCC 0x00137E8C __TEXT __objc_methname
0x1027C2C58 0x00024288 __TEXT __objc_classname
0x1027E6EE0 0x000637A7 __TEXT __objc_methtype
0x10284A690 0x000DCE40 __TEXT __const
0x1029274D0 0x0001C26E __TEXT __ustring
0x102943740 0x001470AC __TEXT __gcc_except_tab
0x102A8A7EC 0x00002C95 __TEXT __swift4_typeref
0x102A8D484 0x000007BC __TEXT __swift4_capture
0x102A8DC40 0x000037C4 __TEXT __swift4_fieldmd
0x102A91410 0x00003914 __TEXT __swift4_reflstr
0x102A94D24 0x00000648 __TEXT __swift4_assocty
0x102A9536C 0x00000370 __TEXT __swift4_proto
0x102A956DC 0x00000484 __TEXT __swift4_types
0x102A95B60 0x000002F8 __TEXT __swift4_builtin
0x102A95E58 0x00000040 __TEXT __swift4_protos
0x102A95E98 0x0000037B __TEXT __dof_RACSignal
0x102A96213 0x000002E8 __TEXT __dof_RACCompou
0x102A964FC 0x00064858 __TEXT __unwind_info
0x102AFAD58 0x000012A8 __TEXT __eh_frame
0x102AFC000 0x000034D0 __DATA __got
0x102AFF4D0 0x00003A68 __DATA __la_symbol_ptr
0x102B02F38 0x000002A8 __DATA __mod_init_func
0x102B031E0 0x00000008 __DATA __mod_term_func
0x102B031F0 0x000D1A58 __DATA __const
0x102BD4C48 0x000B79A0 __DATA __cfstring
0x102C8C5E8 0x0000AF70 __DATA __objc_classlist
0x102C97558 0x000000B0 __DATA __objc_nlclslist
0x102C97608 0x000014C0 __DATA __objc_catlist
0x102C98AC8 0x00000338 __DATA __objc_nlcatlist
0x102C98E00 0x000018A8 __DATA __objc_protolist
0x102C9A6A8 0x00000008 __DATA __objc_imageinfo
0x102C9A6B0 0x004DE908 __DATA __objc_const
0x103178FB8 0x00049C08 __DATA __objc_selrefs
0x1031C2BC0 0x000003D0 __DATA __objc_protorefs
0x1031C2F90 0x00009C08 __DATA __objc_classrefs
0x1031CCB98 0x00006CC8 __DATA __objc_superrefs
0x1031D3860 0x00019894 __DATA __objc_ivar
0x1031ED0F8 0x00084D40 __DATA __objc_data
0x103271E40 0x001563E8 __DATA __data
0x1033C8230 0x000B1818 __DATA __bss
0x103479C00 0x00017C00 __DATA __common
首列是數據在文件的偏移位置,第二列是這一段占用大小,第三列是段類型,代碼段和數據段,第四列是段名稱。
每一行的數據都緊跟在上一行后面,如第二行__stubs的地址0x1024FE744就是第一行__text的地址0x100006C88加上大小0x024F7ABC,整個可執行文件大致數據分布就是這樣。
這里可以清楚看到各種類型的數據在最終可執行文件里占的比例,例如__text表示編譯后的程序執行語句,__data表示已初始化的全局變量,全局及局部靜態變量;__bss表示未初始化的全局靜態變量和局部靜態變量;__common表示未初始化的全局變量;__cstring表示代碼里的字符串常量,等等。
通過解析,我們發現可以通過.data
段來解決plist文件讀取緩慢的問題,因為這塊內容不屬于本章節范圍,所以有興趣的可以參考此文章Use Mach-O section as plist
3
接著就是按上表順序,列出具體的按每個文件列出每個對應字段的位置和占用空間
# Symbols:
# Address Size File Name
0x100006C88 0x00000028 [ 2] +[LKTestDebugManager isDebugUIOpen]
0x100006CB0 0x000000AC [ 2] +[LKTestDebugManager loadDebugDataIfNeed]
0x100006D5C 0x00000264 [ 2] +[LKTestDebugManager showDebugUI]
同樣首列是數據在文件的偏移地址,第二列是占用大小,第三列是所屬文件序號,對應上述Object files列表,最后是名字。
例如第一行代表了文件序號為2(反查上面就是LKTestDebugManager.o)的isDebugUIOpen方法占用了40byte大小。
使用
這個文件可以讓你了解整個APP編譯后的情況,也許從中可以發現一些異常,還可以用這個文件計算靜態鏈接庫在項目里占的大小,有時候我們在項目里鏈了很多第三方庫,導致APP體積變大很多,我們想確切知道每個庫占用了多大空間,可以給我們優化提供方向。LinkMap里有了每個目標文件每個方法每個數據的占用大小數據,LinkMap 下載這個mac工程 然后運行,選擇生成的linkmap.txt,進行分類,輸出文件,就可以統計出每個.o最后的大小,屬于一個.a靜態鏈接庫的.o加起來,就是這個庫在APP里占用的空間大小,我們就可根據該文件進行后續操作。