iOS打包出來的.ipa文件解壓之后,得到Payload文件夾,右鍵顯示包內容得到包里面的內容,但是無法看到可執(zhí)行文件的組成內容及所占大小。
查看.ipa中的文件組成及所占大小。

1.生成LinkMap,更改配置。在Target的Build Settings中更改Write Link Map File 為 Yes,這樣就可以生成Link Map文件了,但是這個文件在哪呢。通過修改Build Settings的Path To Link Map可以指定LinkMap文件的生成目錄,默認是生成在Build文件夾下。
2.編譯后得到LinkMap.txt文件。編譯成功后在路徑下得到/Users/xxxx/Library/Developer/Xcode/DerivedData/HelloWorld-fitgtiqfrissytdwtvkxxhkhpsfq/Build/Intermediates.noindex/HelloWorld.build/Debug-iphonesimulator/HelloWorld.build/HelloWorld-LinkMap-normal-x86_64.txt文件。


- LinkMap文件格式
# Path
# Arch: x86_64
# Object files:
# Sections:
# Symbols:
# Dead Stripped Symbols:
一個完整的LinkMap文件是分為這幾塊的,以#為分隔。
# Path: /Users/xxxx/Library/Developer/Xcode/DerivedData/HelloWorld-fitgtiqfrissytdwtvkxxhkhpsfq/Build/Products/Debug-iphonesimulator/HelloWorld.app/HelloWorld
Path記錄的是這個LinkMap對應的安裝包的地址。
# Arch: x86_64
Arch指的是這個LinkMap對應的架構。
# Object files:
[ 0] linker synthesized
[ 1] /Users/xxxx/Library/Developer/Xcode/DerivedData/HelloWorld-fitgtiqfrissytdwtvkxxhkhpsfq/Build/Intermediates.noindex/HelloWorld.build/Debug-iphonesimulator/HelloWorld.build/HelloWorld.app-Simulated.xcent
[ 2] /Users/xxxx/Library/Developer/Xcode/DerivedData/HelloWorld-fitgtiqfrissytdwtvkxxhkhpsfq/Build/Intermediates.noindex/HelloWorld.build/Debug-iphonesimulator/HelloWorld.build/Objects-normal/x86_64/ViewController.o
[ 3] /Users/xxxx/Library/Developer/Xcode/DerivedData/HelloWorld-fitgtiqfrissytdwtvkxxhkhpsfq/Build/Intermediates.noindex/HelloWorld.build/Debug-iphonesimulator/HelloWorld.build/Objects-normal/x86_64/main.o
[ 4] /Users/xxxx/Library/Developer/Xcode/DerivedData/HelloWorld-fitgtiqfrissytdwtvkxxhkhpsfq/Build/Intermediates.noindex/HelloWorld.build/Debug-iphonesimulator/HelloWorld.build/Objects-normal/x86_64/AppDelegate.o
[ 5] /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/arc/libarclite_iphonesimulator.a(arclite.o)
[ 6] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.4.sdk/System/Library/Frameworks//Foundation.framework/Foundation.tbd
[ 7] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.4.sdk/usr/lib/libobjc.tbd
[ 8] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.4.sdk/usr/lib/libSystem.tbd
[ 9] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.4.sdk/System/Library/Frameworks//CoreFoundation.framework/CoreFoundation.tbd
[ 10] /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.4.sdk/System/Library/Frameworks//UIKit.framework/UIKit.tbd
Object files是編譯后生成的文件列表,比如這個程序class都編譯成了.o文件,像我們比較熟悉的AppDelegate.o文件等等。還有引進來的幾個庫,比如UIKit.tbd。
# Sections:
# Address Size Segment Section
0x100001910 0x00001AD0 __TEXT __text
0x1000033E0 0x00000120 __TEXT __stubs
0x100003500 0x000001F0 __TEXT __stub_helper
0x1000036F0 0x00000BA2 __TEXT __objc_methname
0x100004292 0x00000065 __TEXT __objc_classname
0x1000042F7 0x0000087C __TEXT __objc_methtype
0x100004B73 0x0000024B __TEXT __cstring
0x100004DC0 0x00000008 __TEXT __const
0x100004DC8 0x00000178 __TEXT __entitlements
0x100004F40 0x000000B4 __TEXT __unwind_info
0x100005000 0x00000078 __DATA __got
0x100005078 0x00000010 __DATA __nl_symbol_ptr
0x100005088 0x00000180 __DATA __la_symbol_ptr
0x100005208 0x00000010 __DATA __objc_classlist
0x100005218 0x00000008 __DATA __objc_nlclslist
0x100005220 0x00000018 __DATA __objc_protolist
0x100005238 0x00000008 __DATA __objc_imageinfo
0x100005240 0x00000CF8 __DATA __objc_const
0x100005F38 0x000000B8 __DATA __objc_selrefs
0x100005FF0 0x00000008 __DATA __objc_protorefs
0x100005FF8 0x00000008 __DATA __objc_classrefs
0x100006000 0x00000008 __DATA __objc_superrefs
0x100006008 0x00000008 __DATA __objc_ivar
0x100006010 0x000000F0 __DATA __objc_data
0x100006100 0x00000160 __DATA __data
0x100006260 0x00000180 __DATA __bss
Section是各種數(shù)據類型所在的內存空間,Section主要分為兩大類,__Text和__DATA。__Text指的是程序代碼,__DATA指的是已經初始化的變量等。
具體分類如下表所示。
以下是__TEXT段的section
__text 主程序代碼
stubs 和stub_helper 用于動態(tài)鏈接庫的stub
__cstring c語言字符串
__const const修飾的常量
__objc_methname objc的方法名稱
__objc_methtype objc方法類型
__objc_classname objc類方法
以下是__DATA段的section
__objc_ivars objc類的實例變量
__objc_classlist objc類列表
__objc_protolist objc協(xié)議列表
__objc_imageinfo objc鏡像信息
__objc_const objc常量
__objc_selfrefs objc自引用(self)
__objc_protorefs objc協(xié)議引用
__objc_superrefs objc超類引用
__cfstring 使用Core Foundation字符串
__bss BSS
每個Section前面的兩個16進制的數(shù)字代表的就是這個Section相對于安裝包初始內存的偏移和這個Section的大小。比如:
0x100001910 0x00001AD0 __TEXT __text
__text這個Section的偏移地址是0x100001910,這塊的大小是0x00001AD0,也就是6864個字節(jié)。
# Symbols:
# Address Size File Name
0x100001910 0x00000040 [ 2] -[ViewController viewDidLoad]
0x100001950 0x0000003C [ 2] -[ViewController didReceiveMemoryWarning]
0x100001990 0x00000090 [ 3] _main
0x100001A20 0x00000080 [ 4] -[AppDelegate application:didFinishLaunchingWithOptions:]
0x100001AA0 0x00000040 [ 4] -[AppDelegate applicationWillResignActive:]
0x100001AE0 0x00000040 [ 4] -[AppDelegate applicationDidEnterBackground:]
0x100001B20 0x00000040 [ 4] -[AppDelegate applicationWillEnterForeground:]
0x100001B60 0x00000040 [ 4] -[AppDelegate applicationDidBecomeActive:]
0x100001BA0 0x00000040 [ 4] -[AppDelegate applicationWillTerminate:]
0x100001BE0 0x00000020 [ 4] -[AppDelegate window]
0x100001C00 0x00000040 [ 4] -[AppDelegate setWindow:]
0x100001C40 0x00000033 [ 4] -[AppDelegate .cxx_destruct]
iOS開發(fā)的同學對Symbols這個單詞肯定不陌生,什么Crash要有對應的符號表,編譯的時候經常保持找不到Symbols等。Symbols簡單來說就是類名,變量名,方法名等等符號。所以這一塊也詳細列出了這個安裝包內各個方法所占的內存大小。
這一塊太多了,我只列出一小部分,這塊同樣有四列,一二列和Sections的情況一樣,分別是偏移地址和大小。第四列是方法的符號,類名+方法名。第三列是文件序號,這個序號是哪里來的的,就是前面提到的Object files里文件的序號,比如這里viewDidLoad的序號是2,去Object files去找序號是2的文件。
[ 2] /Users/xxxx/Library/Developer/Xcode/DerivedData/HelloWorld-fitgtiqfrissytdwtvkxxhkhpsfq/Build/Intermediates.noindex/HelloWorld.build/Debug-iphonesimulator/HelloWorld.build/Objects-normal/x86_64/ViewController.o
也就是說這個方法來自ViewController.o這個文件。
通過這種對應關系,我可以知道一個.o文件里有多少方法被編譯進了安裝包,每個方法所占的體積,加起來我就知道每個.o文件的大小了。后面的程序也就是把這個過程給自動化了。
# Dead Stripped Symbols:
# Size File Name
<<dead>> 0x00000018 [ 2] CIE
<<dead>> 0x00000018 [ 3] CIE
<<dead>> 0x00000006 [ 4] literal string: class
<<dead>> 0x00000008 [ 4] literal string: v16@0:8
<<dead>> 0x00000018 [ 4] CIE
<<dead>> 0x0000000F [ 5] literal string: isKindOfClass:
<<dead>> 0x00000005 [ 5] literal string: self
<<dead>> 0x00000008 [ 5] literal string: release
<<dead>> 0x0000000E [ 5] literal string: v32@0:8@16@24
<<dead>> 0x00000018 [ 5] CIE
最后還有一部分是沒用的符號,這部分我也不知道是怎么產生的,但可以肯定的是這部分不應該太大。
3.自動分析:通過前面對LinkMap文件格式的解析,我們知道在LinkMap里,我們可以知道每個文件所占的體積大小,并且可以通過文件的前綴,知道文件所屬的動態(tài)庫,這樣也就可以知道動態(tài)庫的大小。只是這個過程太過繁瑣,所以我們去把它自動化了。項目開源地址:LinkMapParser
- Mac自帶python環(huán)境。Python環(huán)境安裝
? LinkMapParser-master python --version
Python 2.7.10
- 該工具支持分析一個link map文件和比較兩個link map文件,進入下載的開源項目LinkMapParser目錄,運行的命令分別為:
python parselinkmap.py /Users/xxxx/Library/Developer/Xcode/DerivedData/HelloWorld-fitgtiqfrissytdwtvkxxhkhpsfq/Build/Intermediates.noindex/HelloWorld.build/Debug-iphonesimulator/HelloWorld.build/HelloWorld-LinkMap-normal-x86_64.txt

python parselinkmap.py /Users/xxxx/Library/Developer/Xcode/DerivedData/HelloWorld-fitgtiqfrissytdwtvkxxhkhpsfq/Build/Intermediates.noindex/HelloWorld.build/Debug-iphonesimulator/HelloWorld.build/HelloWorld-LinkMap-normal-x86_64.txt /Users/xxxx/Library/Developer/Xcode/DerivedData/AddChildViewController-fmbyhwgpcjsxuzgomqidebjtmwnx/Build/Intermediates.noindex/AddChildViewController.build/Debug-iphonesimulator/AddChildViewController.build/AddChildViewController-LinkMap-normal-x86_64.txt

