iOS包大小计算
一、LinkMap文件分析
说明:LinkMap数据是根据文章《LinkMap文件分析》中方法实验实测数据。
如何获得LinkMap文件
1.在XCode中开启编译选项Write Link Map File \n
XCode -> Project -> Build Settings -> 把Write Link Map File选项设为yes,并指定好linkMap的存储位置
2.工程编译完成后,在编译目录里找到Link Map文件(txt类型)
在Build Settings里Path to Link Map File对应Link Map的路径,以下是默认路径:
/Users/xxx/Library/Developer/Xcode/DerivedData/YourApp/Build/Intermediates.noindex/YourApp.build/Debug-iphoneos/YourApp.build/YourApp-LinkMap-normal-arm64.txt
LinkMap里有了每个目标文件每个方法每个数据的占用大小数据,所以只要写个脚本,就可以统计出每个.o最后的大小,属于一个.a静态链接库的.o加起来,就是这个库在APP里占用的空间大小。
LinkMap包含以下部分:
# Path: .../*.app文件
# Arch: arm64
# Object files: .../*.o文件
# Sections: Text和Data分类大小
# Symbols: 与Object files对应起来,是Object files的详细Symbal信息,包括地址和大小
# Dead Stripped Symbols:
// linkmap.js
var readline = require('readline'),
fs = require('fs'); var LinkMap = function(filePath) {
this.files = []
this.filePath = filePath
} LinkMap.prototype = {
start: function(cb) {
var self = this
var rl = readline.createInterface({
input: fs.createReadStream(self.filePath),
output: process.stdout,
terminal: false
});
var currParser = "";
rl.on('line', function(line) {
if (line[0] == '#') {
if (line.indexOf('Object files') > -1) {
currParser = "_parseFiles";
} else if (line.indexOf('Sections') > -1) {
currParser = "_parseSection";
} else if (line.indexOf('Symbols') > -1) {
currParser = "_parseSymbols";
}
return;
}
if (self[currParser]) {
self[currParser](line)
}
}); rl.on('close', function(line) {
cb(self)
});
}, _parseFiles: function(line) {
var arr =line.split(']')
if (arr.length > 1) {
var idx = Number(arr[0].replace('[',''));
var file = arr[1].split('/').pop().trim()
this.files[idx] = {
name: file,
size: 0
}
}
}, _parseSection: function(line) {
}, _parseSymbols: function(line) {
var arr = line.split('\t')
if (arr.length > 2) {
var size = parseInt(arr[1], 16)
var idx = Number(arr[2].split(']')[0].replace('[', ''))
if (idx && this.files[idx]) {
this.files[idx].size += size;
}
}
}, _formatSize: function(size) {
if (size > 1024 * 1024) return (size/(1024*1024)).toFixed(2) + "MB"
if (size > 1024) return (size/1024).toFixed(2) + "KB"
return size + "B"
}, statLibs: function(h) {
var libs = {}
var files = this.files;
var self = this;
for (var i in files) {
var file = files[i]
var libName
if (file.name.indexOf('.o)') > -1) {
libName = file.name.split('(')[0]
} else {
libName = file.name
}
if (!libs[libName]) {
libs[libName] = 0
}
libs[libName] += file.size
}
var i = 0, sortLibs = []
for (var name in libs) {
sortLibs[i++] = {
name: name,
size: libs[name]
}
}
sortLibs.sort(function(a,b) {
return a.size > b.size ? -1: 1
})
if (h) {
sortLibs.map(function(o) {
o.size = self._formatSize(o.size)
})
}
return sortLibs
}, statFiles: function(h) {
var self = this
self.files.sort(function(a,b) {
return a.size > b.size ? -1: 1
})
if (h) {
self.files.map(function(o) {
o.size = self._formatSize(o.size)
})
}
return this.files
}
} if (!process.argv[2]) {
console.log('usage: node linkmap.js filepath -hl')
console.log('-h: format size')
console.log('-l: stat libs')
return
}
var isStatLib, isFomatSize
var opts = process.argv[3];
if (opts && opts[0] == '-') {
if (opts.indexOf('h') > -1) isFomatSize = true
if (opts.indexOf('l') > -1) isStatLib = true
} var linkmap = new LinkMap(process.argv[2])
linkmap.start(function(){
var ret = isStatLib ? linkmap.statLibs(isFomatSize)
: linkmap.statFiles(isFomatSize)
for (var i in ret) {
console.log(ret[i].name + '\t' + ret[i].size)
}
})
执行:
node linkmap.js LinkMap-normal-arm64.txt -hl
得到:
YourSDK(YourSDK-arm64-master.o) 122.76KB
二、xcodebuild总包大小分析
分析:Release 包(arm64)为什么比debug包(x86_64)大那么多?
分析步骤
1. 抽出YourSDK的arm64看包大小(1.6M)
lipo -thin arm64 -output YourSDK_arm64.a YourSDK.framework/YourSDK
➜ ls -al YourSDK_arm64.a
-rw-r--r-- 1 yushu.lxy staff 1606208 11 18 15:58 YourSDK_arm64.a
2. 整体
size YourSDK_armv64.a
__TEXT __DATA __OBJC others dec hex
86591 39492 0 1190617 1316700 14175c YourSDK_arm64.a(YourSDK-arm64-master.o)
30 240 0 4566 4836 12e4 YourSDK_arm64.a(libPods-YourSDK.a-arm64-master.o)
查看.a文件下.o文件大小
ar -t -v YourSDK_arm64.a
rw-r--r-- 501/20 5776 Nov 18 15:58 2019 __.SYMDEF SORTED
rw-r--r-- 0/0 1593168 Jan 1 08:00 1970 YourSDK-arm64-master.o
rw-r--r-- 0/0 6976 Jan 1 08:00 1970 libPods-YourSDK.a-arm64-master.o
3. 详细
size -m YourSDK_arm64.a
YourSDK_arm64.a(YourSDK-arm64-master.o):
Segment : 1316713
Section (__TEXT, __text): 68676(比debug的包小)
Section (__TEXT, __objc_methname): 8393
Section (__TEXT, __cstring): 5091
Section (__TEXT, __objc_classname): 1636
Section (__TEXT, __objc_methtype): 1937
Section (__TEXT, __literal16): 128(只有debug包有)
Section (__TEXT, __literal4): 8(只有debug包有)
Section (__TEXT, __literal8): 144(比debug的包小)
Section (__TEXT, __eh_frame): 16480
Section (__TEXT, __gcc_except_tab): 608
Section (__TEXT, __ustring): 42
Section (__TEXT, __const): 64
Section (__DATA, __const): 1560
Section (__DATA, __cfstring): 4736
Section (__DATA, __objc_classlist): 400
Section (__DATA, __objc_catlist): 8
Section (__DATA, __objc_protolist): 56
Section (__DATA, __objc_imageinfo): 8
Section (__DATA, __objc_const): 24224
Section (__DATA, __objc_selrefs): 2752
Section (__DATA, __objc_protorefs): 8
Section (__DATA, __objc_classrefs): 592
Section (__DATA, __objc_superrefs): 192
Section (__DATA, __objc_ivar): 252(比debug的包小)
Section (__DATA, __objc_data): 4000
Section (__DATA, __data): 672
Section (__DATA, __bss): 32
Section (__LD, __compact_unwind): 11424
Section (__LLVM, __bundle): 1179193(+)
total 1316700
total 1316713
YourSDK_arm64.a(libPods-YourSDK.a-arm64-master.o):
Segment : 4838
Section (__TEXT, __text): 0
Section (__TEXT, __objc_classname): 30
Section (__DATA, __objc_classlist): 8
Section (__DATA, __objc_imageinfo): 8
Section (__DATA, __objc_const): 144
Section (__DATA, __objc_data): 80
Section (__LLVM, __bitcode): 4480 (+)
Section (__LLVM, __cmdline): 86 (+)
total 4836
total 4838
YourSDK SDK实际大小应该是:1316713-1179193 = 137KB(与LinkMap分析接近)
分析:
上面段数据LLVM bundle部分是release包比debug包大的原因,是因为release包包含了bitCode数据。
(1)bitcode是源码和机器码之间的中间形式。
(2)为什么苹果要强推bitcode?开发者把bitcode提交到App Store Connect之后,如果苹果发布了使用新芯片的iPhone,支持更高效的指令,开发者不需要做任何操作,App Store Connect自己就可以编译出针对新产品优化过的app并通过App Store分发给用户,不需要开发者自己重新打包上架。
(3)苹果可以将bitcode代码进行一些逻辑等价的转换,使得代码的执行效率更高,体积更小。
实验:APP的project开启bitcode和关闭bitcode,查看手机中app的实际大小,开启bitcode的包更小。
size -m YourSDK_arm64.a
YourSDK_arm64.a(YourSDK-arm64-master.o):
Segment : 943490
Section (__TEXT, __text): 53184
Section (__TEXT, __objc_classname): 633
Section (__TEXT, __objc_methname): 7919
Section (__TEXT, __objc_methtype): 850
Section (__TEXT, __cstring): 7352
Section (__TEXT, __literal8): 64
Section (__TEXT, __gcc_except_tab): 1724
Section (__TEXT, __const): 112
Section (__DATA, __const): 1864
Section (__DATA, __cfstring): 4000
Section (__DATA, __objc_classlist): 200
Section (__DATA, __objc_protolist): 8
Section (__DATA, __objc_imageinfo): 8
Section (__DATA, __objc_const): 21760
Section (__DATA, __objc_selrefs): 1776
Section (__DATA, __objc_classrefs): 352
Section (__DATA, __objc_superrefs): 24
Section (__DATA, __objc_ivar): 620
Section (__DATA, __objc_data): 2000
Section (__DATA, __data): 96
Section (__DATA, __bss): 40
Section (__DATA, __common): 8
Section (__LD, __compact_unwind): 15968
Section (__LLVM, __bundle): 822914
total 943476
total 943490
分析结论
(1) LinkMap分析的大小不包含打入framework中的bundle信息,建议用LinkMap分析的包大小至少要加上bundle的大小。
(2)经多次安装实验,真实安装包后, APP大小增长是比LinkMap给出的包大小大的。
(3)给外部的包大小信息,暂时跟大家保持一致“使用LinkMap给出的数据”。
iOS包大小计算的更多相关文章
- (一一七)基本文件操作 -SDWebImage清除缓存 -文件夹的大小计算
在iOS的App沙盒中,Documents和Library/Preferences都会被备份到iCloud,因此只适合放置一些记录文件,例如plist.数据库文件.缓存一般放置到Library/Cac ...
- [转]SOCKET通信中TCP、UDP数据包大小的确定
TCP.UDP数据包大小的确定 UDP和TCP协议利用端口号实现多项应用同时发送和接收数据.数据通过源端口发送出去,通过目标端口接收.有的网络应用只能使用预留或注册的静态端口:而另外一些网络应用则可以 ...
- SQLSERVER复制优化之一《改变包大小》
SQLSERVER复制优化之一<改变包大小> 自从搭了复制之后以为可以安枕无忧了,谁不知问题接踵而来 这次遇到的问题是丢包,不知道情况的读者可以先看一下我之前写的一篇<SQLSERV ...
- C++类所占内存大小计算
C++类所占内存大小计算 说明:笔者的操作系统是32位的. class A {}; sizeof( A ) = ? sizeof( A ) = 1明明是空类,为什么编译器说它是1呢? 空类同样可以实例 ...
- apk瘦身(包大小优化)
最近太忙好久没有写随笔,放假才有空写写随笔. 最近在项目中一直在做包大小优化 随着业务需求的增加,包大小是忍不住的往上涨 为了提高应用市场下载转化率,一直在优化包大小 首先 分析你的apk中占比的主要 ...
- [转]TCP、UDP数据包大小的确定
TCP.UDP数据包大小的确定 http://blog.163.com/jianlizhao%40126/blog/static/1732511632013410101827640/ U ...
- TCP、UDP数据包大小的限制(UDP数据包一次发送多大为好)——数据帧的物理特性决定的,每层都有一个自己的数据头,层层递减
1.概述 首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层. 其中以太网(Ethernet)的数据帧在链路层 IP包在网络层 TCP或UDP包在传输层 TCP或UDP中的数据(Da ...
- SQLSERVER复制优化之一《减少包大小》
原文:SQLSERVER复制优化之一<减少包大小> SQLSERVER复制优化之一<减少包大小> 自从搭了复制之后以为可以安枕无忧了,谁不知问题接踵而来 这次遇到的问题是丢包, ...
- UDP传输包大小(转)
源:UDP传输包大小 在进行UDP编程的时候,我们最容易想到的问题就是,一次发送多少bytes好? 当然,这个没有唯一答案,相对于不同的系统,不同的要求,其得到的答案是不一样的,我这里仅对 像ICQ一 ...
- mysql查询进程、导入数据包大小设置
mysql查询进程.导入数据包大小设置 zoerywzhou@163.com http://www.cnblogs.com/swje/ 作者:Zhouwan 2017-12-27 查询正在执行的进程: ...
随机推荐
- 14.java 中缀表达式转后缀表达式
思路如下: 1.初始化两个栈,运算符栈和中间结果栈 2.从左至右扫描 3.遇到数时直接压入s2 4.遇到运算符时,比较其与s1栈顶的优先级,有如下几种情况: 1)s1为空或栈顶为"(&quo ...
- jQuery对象和js对象是怎样转换的?
两种转换方式将一个jQuery对象转换成js对象:[index]和.get(index); (1)jQuery对象是一个数据对象,可以通过[index]的方法,来得到相应的js对象. 如:var $v ...
- string中的stoi()函数
1094 谷歌的招聘 (20分) 本题要求你编程解决一个更通用的问题:从任一给定的长度为 L 的数字中,找出最早出现的 K 位连续数字所组成的素数. 输入格式: 输入在第一行给出 2 个正整数,分别是 ...
- ptyhon基础课程_2
10 输入 # 例一 user_name = input ("请输入姓名:") message = user_name + "shaobing" print ( ...
- 使用 docker-compose 安装 es、kibana、mysql、redis、kafka
由于经常的安装虚拟机,每次都要重装环境比较麻烦. 这次写了一个 docker-compose 文件,一次性搞定安装问题. 目录结果如下: --- version: "3.1" ne ...
- 使用ADB拷贝Android设备的文件夹
在当前目录下执行,拷贝到当前目录. 拷贝照片 adb pull sdcard/DCIM 删除照片 adb shell rm -rvf sdcard/DCIM 拷贝图片 adb pull s ...
- py07-文件处理
"""什么是文件? 操作系统提供给用户操作复杂硬件(硬盘)的简易的接口 为什么操作文件 人或者应用程序需要永久的保存数据 如何用 f = open() f.read() ...
- js原型,继承
javascript是为了成为轻量级的语言而开发的.开发者并没有选择像其他面向对象的语言一样,定义类(class),而是使用了protopype实现继承. 每一个函数在创建时,都会创建它的Protot ...
- 记录自己在对订单进行按日期查询时使用的一种查询的方法,这里的orders是订单表,你也可以改成别的什么表对于最终数据不会造成影响,除非你那个表的数据只有几条那样就会出现查不到日期的情况
SELECT @date := DATE_ADD(@date, INTERVAL + 1 DAY) days FROM ( SELECT @date := DATE_ADD("2019-06 ...
- C# string的2个特殊方法
1. Strings.Join 方法:用指定的连接符连接一个数组中包含的若干子字符串创建的字符串.e.g List<string> list = new List<string> ...