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 查询正在执行的进程: ...
随机推荐
- xh_零基础网站渗透第一部
一.认识常见网站类型 1.1asp:asp是动态服务器页面(active server page)的英文缩写.是微软公司开发的代替cgi脚本程序的一种应用,它可以与数据库和其它程序进行交互,是一种简单 ...
- 国产DP4344兼容替代CSM4344 192K双通道输出数模转换芯片
DP4344 是一款完整的 2 通道输出数模转换芯片, 内含插值滤波器.Multi-Bit 数模转换器.输出模 拟滤波器,并支持大部分的音频数据格式.DP4344 基于一个带线性模拟低通滤波器的四阶 ...
- EMQX 在 Kubernetes 中如何进行优雅升级
背景 为了降低 EMQX 在 Kubernetes 上的部署.运维成本,我们将一些日常运维能力进行总结.抽象并整合到代码中,以 EMQX Kubernetes Operator 的方式帮助用户实现 E ...
- (一)从路由器和IP地址开始折腾
我们应当知道的一点是,由于IP地址只有32bit, 所以很快就面临着不够用的情况,现在之所以大家还在正常使用IPv4, 就是因为采用了公有地址和私有地址的概念:所谓的私有地址是从当时公有地址中还没有分 ...
- rabbitMQ queue属性
Map<String, Object> args = new HashMap<String, Object>(); args.put("x-message-ttl&q ...
- 《ImageNet Classification with Deep Convolutional Neural Networks (AlexNet)2012》
Abstract 作者训练了一个大型的深度卷积神经网络,用于在 ImageNet LSVRC-2010 比赛中对120万张高分辨率图像分为1000个不同的类别.在测试数据上,作者们达到了 top-1 ...
- 头条二面:宕机后,Redis如何实现快速恢复?
Redis作为非常火热的内存数据库,其除了具有非常高的性能之外,还需要保证高可用,在故障发生时,尽可能地降低故障带来的影响,Redis也提供了完善的故障恢复机制:哨兵.下面就来具体来看看Redis的故 ...
- Finance财务软件(支持Excel模板打印专题)
我们可以修改模板文件./service/PrintTemplate/凭证打印模板_v1.xlsx 模板中的字段对应 2010_upgrade_01.sql 中的存储过程sp_voucher_print ...
- cc1
基础 cc接口及类介绍 Transformer接口 Defines a functor interface implemented by classes that transform one obje ...
- 大二下学期开学java测试
我们在2月13日下午进行了java测试(是一个新闻类型的题),通过这一个测试我进行了以下总结: 我对于javaweb的框架构建和加密密码,还有一些不同人物功能的实现,使得我在这次得考试中成绩不太理想. ...