iOS 动态 Framework 对App启动时间影响实测
最近看到的Slow App Startup Times里提到:
The dynamic loader finds and reads the dependent dynamic libraries (dylibs) used by the App. Each library can itself have dependencies. The loading of Apple system frameworks is highly optimized but loading your embedded frameworks can be expensive. To speed up dylib loading Apple suggests you use fewer dylibs or consider merging them A suggested target is for six extra (non-system) frameworks.
至于什么是static lib什么是dynamic lib这里就不展开提了,大家可以通过在文章底部的相关链接去详细了解。
引用一下官方的解释就是:
- A better approach is for an app to load code into its address space when it’s actually needed, either at launch time or at runtime. The type of library that provides this flexibility is called dynamic library.
- When an app is launched, the app’s code—which includes the code of the static libraries it was linked with—is loaded into the app’s address space.Applications with large executables suffer from slow launch times and large memory footprints
如果给你一个简单的概念就是如果你的framework使用了swift就是dynamic lib。这也是本文要对比的主题:动态的framework对app启动时间影响到底多大。
测试的方法就采用 iOS 10 提供的新的环境变量 DYLD_PRINT_STATISTICS
输出的app启动时间。Xcode的版本是8.1,测试设备是iphone 6。cocoapod版本1.1。
注意,测试过程发现每次获得的时间统计都不一致,所以我这里的数据可能和你自己测试得到的不同,但是我认为这种偏差不影响定性。
基准线:空的OC项目 VS 空的Swift项目
创建两个没有任何业务逻辑的空的项目。


大概有10毫秒的差异。这个差距考虑到测量的偏差可以认为两者几乎是一致的。
但是有时会出现swift加载忽然提高到400ms的情况。这是因为系统的动态framework只会加载一份。假设10个app启动都用到了UIKit,系统内部也只加载了一份UIKit。所以有时swift项目启动的时候刚好用到了系统framework没有缓存,就会显得的长一点。
6个framework
现在我们对比有代码的情况。两个项目分别加入5个依赖。
这是OC项目的6个依赖:
pod 'AFNetworking', '~> 3.0'
pod 'Masonry'
pod 'MJRefresh'
pod 'SDWebImage'
pod 'MBProgressHUD'
pod 'IQKeyboardManager'
这是swift项目的6个依赖,为了模拟真实生产中依然使用一些OC库的情况,将3个库换成了swift编码的,保留了3个OC库:
pod 'Alamofire'
pod 'SnapKit'
pod 'MJRefresh'
pod 'Kingfisher'
pod 'MBProgressHUD'
pod 'IQKeyboardManager'
OC的启动时间在70-100ms左右。这里取快的情况的数据:

swift项目在第一次安装时的启动时间在dylib会多100ms,不知为何。swift项目在已经安装后运行打开的成绩:

列一个横向对比图:

结论
swift项目的dylib时间相比OC多了一百多毫秒,远远大于OC。
Swift 不使用framework VS 使用framework
我们猜测是不是加载framework导致时间增大很多呢。所以我们把这些依赖的代码全部放在主app里,不使用framework分离。这次我们把几个依赖的库全部换成swift:
pod 'Alamofire'
pod 'SnapKit'
pod 'Kingfisher'
pod 'SwiftDate'
pod 'ObjectMapper'
5个依赖的项目在app已经安装,运行打开结果:

考虑到误差可以认为framework里的代码是OC还是swift对于加载时间的影响并不大。
把依赖的代码全都合并到App里,就是采取手工拷贝的方式:

安装后打开的启动时间统计:

对比图:

结论
如果把代码收到拷贝进app里,可以显著降低dylib加载时间。
15个framework OC VS Swift
OC的podfile:
pod 'AFNetworking', '~> 3.0'
pod 'Masonry'
pod 'MJRefresh'
pod 'SDWebImage'
pod 'MBProgressHUD'
pod 'IQKeyboardManager'
pod 'FMDB'
pod 'GPUImage'
pod 'OpenUDID'
pod 'DateTools'
pod 'TMCache'
pod 'WebViewJavascriptBridge'
pod 'ZBarSDK'
pod 'JSQMessagesViewController'
pod 'YYKit'
pod 'DZNEmptyDataSet'
swift项目的podfile:
pod 'AFNetworking', '~> 3.0'
pod 'Alamofire'
pod 'SnapKit'
pod 'MJRefresh'
pod 'Kingfisher'
pod 'MBProgressHUD'
pod 'IQKeyboardManager'
pod 'FMDB'
pod 'GPUImage'
pod 'OpenUDID'
pod 'SwiftDate'
pod 'CryptoSwift'
pod 'ObjectMapper'
pod 'ZBarSDK'
pod 'CocoaLumberjack/Swift'
pod 'YYKit'
pod 'DZNEmptyDataSet'
OC的结果:

swift的结果:

对比图:

纵向对比:

结论
OC的项目随着依赖增多,初始化时间增大,但是dylib时间增加不明显。swift则dylib时间大幅增加,初始化时间变化不大。总的启动时间比OC多了200多毫秒,随着framework的增多,启动时间差距拉大。
25个dynamic framework
如果把dylib提高到25个时间又会增长多少呢。
在15个基础上再添加10个依赖:
pod 'EZSwiftExtensions'
pod 'ReactiveCocoa', '5.0.0-alpha.3'
pod 'RxSwift', '~> 3.0'
pod 'RxCocoa', '~> 3.0'
pod 'MonkeyKing'
pod 'Reusable'
pod 'SwiftyJSON'
pod 'XCGLogger'
pod 'Gifu', '~> 2.0.0-rc'
pod 'Spring', :git => 'https://github.com/MengTo/Spring.git', :branch => 'swift3'
运行时间:

和15个dylib的时候的对比:

dylib加载时间从400增加到600,增加了30%左右。dylib数量从15到25个增加40%。接近线性。
总结
毫无疑问,使用了dynamic framework后会增加app启动时间。如果你的数量在25个左右,相比OC的静态framework启动时间会增加0.5s左右。我个人对于iOS提高加载framework的时间不太抱有希望,苹果让自定义的framework常驻内存似乎也无望,这个时间短期内可能无法抹平。
如果人为的把一些外部依赖手动管理在一个framework也是可行,但是如果复杂一点包的互相依赖的情况会比较费心。
如果公司对性能有着苛刻要求可能500ms是难以忍受的。但是我觉得对于大多数产品而言,牺牲这500ms的性能相比于使用OC,我觉得还是用OC比较难受。
相关链接:
WWDC 2016 Session 406 Optimizing App Startup Time
What are Frameworks?
iOS 开发中的『库』(一)
jverkoey/iOS-Framework
原文链接:http://www.jianshu.com/p/3263009e9228
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
iOS 动态 Framework 对App启动时间影响实测的更多相关文章
- 实测iOS Dynamic Framework 对 App 启动时间的影响效果
最近看到的Slow App Startup Times里提到: The dynamic loader finds and reads the dependent dynamic libraries ( ...
- 【转】iOS动态库和静态库的简要介绍
静态库与动态库的区别 首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别人使用. 什么时候我们会用到库呢?一种情况是某些代码需要给别人使用,但是我们不希望别人 ...
- iOS动态部署方案
转载: iOS动态部署方案 前言 这里讨论的动态部署方案,就是指通过不发版的方式,将新的内容.新的业务流程部署进已发布的App.因为苹果的审核周期比较长,而且苹果的限制比较多,业界在这里也没有特别多的 ...
- iOS - GitHub干货分享(APP引导页的高度集成 - DHGuidePageHUD - ②)
距上一篇博客"APP引导页的高度集成 - DHGuidePageHUD - ①"的发布有一段时间了, 后来又在SDK中补充了一些新的内容进去但是一直没来得及跟大家分享, 今天来跟大 ...
- iOS 跳转到 App Store 下载评分页面
html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...
- 关于IOS的证书、App ID、设备、Provisioning Profile详述
首先,打开developer.apple.com ,在iOS Dev Center打开Certificates, Indentifiers & Profiles认识一下基本结构.列表就包含了开 ...
- iOS开发UI篇—APP主流UI框架结构
iOS开发UI篇—APP主流UI框架结构 一.简单示例 说明:使用APP主流UI框架结构完成简单的界面搭建 搭建页面效果: 二.搭建过程和 ...
- ele.me在IOS浏览器端启动APP的技巧分析
ele.me在IOS浏览器端启动APP的技巧分析 巧妙利用后台重定向,在schemes启动时提示用户打开,启动不了APP时能够及时跳转至下载页面. 避免报错页面的出现以及用户还没来的及选择就跳转到下载 ...
- Appium+python自动化19-iOS模拟器(iOS Simulator)安装自家APP
前言 做过iOS上app测试的小伙伴应该都知道,普通用户安装app都是从appstore下载安装,安装测试版本的app,一般就是开发给的二维码扫码安装, 或者开发给个.ipa的安装包文件,通过itoo ...
随机推荐
- [LeetCode] Prefix and Suffix Search 前后缀搜索
Given many words, words[i] has weight i. Design a class WordFilter that supports one function, WordF ...
- python爬虫——爬取小说 | 探索白子画和花千骨的爱恨情仇(转载)
转载出处:药少敏 ,感谢原作者清晰的讲解思路! 下述代码是我通过自己互联网搜索和拜读完此篇文章之后写出的具有同样效果的爬虫代码: from bs4 import BeautifulSoup imp ...
- SQL学习之查询
查询实例: 1.创建数据库并使用: create database school; use school; 2.创建表并插入内容: create table student( Sno char(9) ...
- [Codeforces 940E]Cashback
Description 题库链接 给你两个整数 \(n,c\) ,以及一个数列 \(A\) ,让你将序列分为许多段.对于每一段,他的价值为序列内除了最小的 \(\left\lfloor\frac{le ...
- [JLOI 2011]飞行路线&[USACO 09FEB]Revamping Trails
Description Alice和Bob现在要乘飞机旅行,他们选择了一家相对便宜的航空公司.该航空公司一共在n个城市设有业务,设这些城市分别标记为0到n-1,一共有m种航线,每种航线连接两个城市,并 ...
- [Luogu 3902]Increasing
Description Input Output Sample Input 3 1 3 2 Sample Output 1 HINT 题解 由于题目要求我们求严格递增的数列,即: $$A[i]> ...
- [CQOI2013]新Nim游戏
Description 传统的Nim游戏是这样的:有一些火柴堆,每堆都有若干根火柴(不同堆的火柴数量可以不同).两个游戏者轮流操作,每次可以选一个火柴堆拿走若干根火柴.可以只拿一根,也可以拿走整堆火柴 ...
- HDU 4526 拼车记
话说威威猫有一次去参加比赛,虽然学校离比赛地点不太远,但威威猫还是想坐出租车去.大学城的出租车总是比较另类,有“拼车”一说,也就是说,你一个人坐车去,还是一堆人一起,总共需要支付的钱是一样的(每辆出租 ...
- [BZOJ]3110 K大数查询(ZJOI2013)
这大概是唯一一道小C重写了4次的题目. 姿势不对的树套树(Fail) → 分块(Fail) → 整体二分(Succeed) → 树套树(Succeed). 让小C写点心得静静. Description ...
- HWM、PCTFREE、PCTUSED
什么是水线(High Water Mark)? HWM通常增长的幅度为一次5个数据块,原则上HWM只会增大,不会缩小,即使将表中的数据全部删除,HWM还是为原值,由于这个特点,使HWM很象一个水库的历 ...