iOS 可執行文件組成

iOS APP編譯后,除了一些資源文件,剩下的就是一個可執行文件,有時候項目大了,引入的庫多了,可執行文件很大,想知道這個可執行文件的構成是怎樣,里面的內容都是些什么,哪些庫占用空間較高,可以用以下方法:

  1. XCode開啟編譯選項Write Link Map File
    XCode -> Project -> Build Settings -> 搜map -> 把Write Link Map File選項設為yes,并指定好linkMap的存儲位置


    linkmap
  2. 編譯后,到編譯目錄里找到該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里占用的空間大小,我們就可根據該文件進行后續操作。

分類后的庫所占空間大小

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。