iOS启动分为两个时间:
Xcode 提供了一个很赞的方法,只需要在 Edit scheme -> Run -> Arguments 中将环境变量 DYLD_PRINT_STATISTICS 设为 1,就可以看到 main 之前各个阶段的时间消耗
Total pre-main time: 341.32 milliseconds (100.0%)
dylib loading time: 154.88 milliseconds (45.3%)
rebase/binding time: 37.20 milliseconds (10.8%)
ObjC setup time: 52.62 milliseconds (15.4%)
initializer time: 96.50 milliseconds (28.2%)
slowest intializers :
libSystem.dylib : 4.07 milliseconds (1.1%)
libMainThreadChecker.dylib : 30.75 milliseconds (9.0%)
AFNetworking : 19.08 milliseconds (5.5%)
LDXLog : 10.06 milliseconds (2.9%)
Bigger : 7.05 milliseconds (2.0%)
还有一个方法获取更详细的时间,只需将环境变量 DYLD_PRINT_STATISTICS_DETAILS 设为 1 就可以。
total time: 2.8 seconds (100.0%)
total images loaded: 488 (471 from dyld shared cache)
total segments mapped: 61, into 24958 pages
total images loading time: 1.1 seconds (40.6%)
total load time in ObjC: 92.39 milliseconds (3.2%)
total debugger pause time: 794.39 milliseconds (28.2%)
total dtrace DOF registration time: 0.00 milliseconds (0.0%)
total rebase fixups: 921,005
total rebase fixups time: 109.77 milliseconds (3.9%)
total binding fixups: 694,265
total binding fixups time: 766.41 milliseconds (27.2%)
total weak binding fixups time: 9.05 milliseconds (0.3%)
total redo shared cached bindings time: 768.13 milliseconds (27.3%)
total bindings lazily fixed up: 0 of 0
total time in initializers and ObjC +load: 690.73 milliseconds (24.5%)
libSystem.B.dylib : 11.67 milliseconds (0.4%)
libBacktraceRecording.dylib : 12.06 milliseconds (0.4%)
libobjc.A.dylib : 6.09 milliseconds (0.2%)
libMainThreadChecker.dylib : 59.50 milliseconds (2.1%)
libViewDebuggerSupport.dylib : 7.66 milliseconds (0.2%)
libglInterpose.dylib : 286.97 milliseconds (10.2%)
libMTLCapture.dylib : 4.28 milliseconds (0.1%)
AWUnityFramework : 103.15 milliseconds (3.6%)
AiWayFashionCar : 365.65 milliseconds (12.9%)
total symbol trie searches: 1594338
total symbol table binary searches: 0
total images defining weak symbols: 63
total images using weak symbols: 133
在项目优化实践中,我们移除了一个没有必要的动态库,并将几个动态库合成为一个动态库,减少动态库数量
第一个阶段:pre-main time 中第一个阶段 dylib loading time : 动态库加载阶段
***注: ***
如何查看动态库的个数: Products 中.app中会有Frameworks文件夹 里面即App需要引入的动态库
举例:Flutter优化日志
这里区分两种方式加载Flutter:
区别:
1. 第一种方式会将flutter依赖的第三方插件做成pod子仓的形式直接引入的源码,
App.framework Flutter.framework
2. 第二种方式会将flutter依赖的第三方插件做成framework,之后将所有的framework做成pod仓库
App.framework, FlutterPluginRegistrant.framework ,shared_preferences.framework, wakelock.framework , FMDB.framework , flutter_boost.framework , sqflite.framework , webview_flutter.framework, Flutter.framework , path_provider.framework , video_player.framework造成的后果是: 第二种主工程会引入很多framework,造成的影响是动态库加载时间变长
第一种:采取直接污染主工程方式: 由于日志较多,仅展示敏感数据
Total pre-main time: 685.23 milliseconds (100.0%) dylib loading time: 152.81 milliseconds (22.3%) rebase/binding time: 74.06 milliseconds (10.8%) ObjC setup time: 44.86 milliseconds (6.5%) initializer time: 413.48 milliseconds (60.3%) Total pre-main time: 980.53 milliseconds (100.0%) dylib loading time: 163.32 milliseconds (16.6%) rebase/binding time: 86.59 milliseconds (8.8%) ObjC setup time: 223.50 milliseconds (22.7%) initializer time: 507.11 milliseconds (51.7%)第二种:采取pod仓库形式
Total pre-main time: 818.21 milliseconds (100.0%) dylib loading time: 243.54 milliseconds (29.7%) rebase/binding time: 72.09 milliseconds (8.8%) ObjC setup time: 39.28 milliseconds (4.8%) initializer time: 463.27 milliseconds (56.6%) Total pre-main time: 1.3 seconds (100.0%) dylib loading time: 270.75 milliseconds (20.3%) rebase/binding time: 69.74 milliseconds (5.2%) ObjC setup time: 282.78 milliseconds (21.2%) initializer time: 708.54 milliseconds (53.2%)对比结果: dylib loading time 时间拉长了100多毫秒
技术选择:
- 第一种方式污染主工程: 可以看到结果是framework变少
- 第二种方式极少的污染主工程: 结果是framework变多
这一阶段系统主要注册 Objc 类。所以,指针数量越少越好。这一步能做的优化有:
核心思想是在进行动态库的重定位和绑定(Rebase/binding)(ASLR:dylib会被加载到随机地址,这个随机的地址跟代码和数据指向的旧地址会有偏差,dyld 需要修正这个偏差,做法就是将 dylib 内部的指针地址都加上这个偏移量) 过程中减少指针修正;
减少Objective-C类数量,减少分类,减少实例变量和函数(删除不用的类以及冗余代码,再深一点就是减少第三方工具的使用,可以查看源码,自己实现);
减少C++虚函数;
Objc Setup Time
这一步主要做了以下操作
注册Objc类 (class registration)
把category的定义插入方法列表 (category registration)
保证每一个selector唯一 (selctor uniquing)
前两部做好之后这一步就没有什么可以有优化的
这一阶段 dyld开始运行程序的初始化函数,调用每个Obj类和分类的+load方法,
这一阶段,dyld 开始运行程序的初始化函数,调用每个 Objc 类和分类的 +load 方法,调用 C/C++ 中的构造器函数。initializer阶段执行完后,dyld 开始调用 main() 函数。在这一步,检查 +load 方法,尽量把事情推迟到 +initiailize 方法里执行。
- 使用initialize替代load方法
- 减少使用c/c++的attribute((constructor));推荐使用dispatch_once(),peathrd_once(), std:once()等方法
- 不要在初始化中创建线程
- 推荐使用swift
优化前
Total pre-main time: 731.83 milliseconds (100.0%)
dylib loading time: 250.62 milliseconds (34.2%)
rebase/binding time: 50.32 milliseconds (6.8%)
ObjC setup time: 37.81 milliseconds (5.1%)
initializer time: 393.07 milliseconds (53.7%)
slowest intializers :
libSystem.B.dylib : 6.20 milliseconds (0.8%)
libMainThreadChecker.dylib : 28.41 milliseconds (3.8%)
libglInterpose.dylib : 187.20 milliseconds (25.5%)
AiWayFashionCar : 244.98 milliseconds (33.4%)
优化后
Total pre-main time: 667.68 milliseconds (100.0%)
dylib loading time: 237.69 milliseconds (35.6%)
rebase/binding time: 53.64 milliseconds (8.0%)
ObjC setup time: 36.47 milliseconds (5.4%)
initializer time: 339.86 milliseconds (50.9%)
slowest intializers :
libSystem.B.dylib : 6.05 milliseconds (0.9%)
libMainThreadChecker.dylib : 28.70 milliseconds (4.2%)
libglInterpose.dylib : 152.15 milliseconds (22.7%)
AiWayFashionCar : 218.33 milliseconds (32.7%)
// 经全局查找看到有一个load方法里面执行了IO操作相关API, 优化之后 initializer time 有所优化
main 到 didFinishLaunching 结束或者第一个 ViewController 的viewDidAppear 都是作为 main 之后启动时间的一个度量指标。
这个时间统计直接打点计算就可以,不过当遇到时间较长需要排查问题时,只统计两个点的时间其实不方便排查,目前见到比较好用的方式就是为把启动任务规范化、粒子化,针对每个任务都有打点统计,这样方便后期问题的定位和优化。
以此记录优化启动日志
最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上
我想用Capistrano启动sidekiq。下面是代码namespace:sidekiqdotask:startdorun"cd#{current_path}&&bundleexecsidekiq-c10-eproduction-Llog/sidekiq.log&"pcapture("psaux|grepsidekiq|awk'{print$2}'|sed-n1p").strip!endend它执行成功但sidekiq仍然没有在服务器上启动。输出:$capsidekiq:starttriggeringloadcallbacks*2014-06-0315:03:01executing`
我有一个正在升级到Rails3的Rails2.3.5应用程序。我做了所有我需要做的升级以及当我使用启动Rails服务器时要做的事情railsserver它给了我这个PleaseswitchtoRuby1.9'sstandardCSVlibrary.It'sFasterCSVplussupportforRuby1.9'sm17nencodingengine.我正在使用ruby-1.9.2-p0并安装了fastercsv(1.5.3)gem。在puts语句的帮助下,我能够追踪到错误发生的位置。我发现执行在这一行停止了Bundler.require(:default,Rails.env)if
电脑启动出现显示器黑屏是一个相当常见的问题。如果您遇到了这个问题,不要惊慌,因为它有很多可能的原因,可以采取一些简单的措施来解决它。在本文中,小编将介绍下面4种常见的电脑启动后显示器黑屏的原因,排查这些原因,快速解决! 演示机型:联想Ideapad700-15ISK-ISE系统版本:Windows10一、显示器问题如果出现电脑启动后显示器黑屏的情况。那么首先您需要检查一下显示器是否正常工作。您可以通过更换另一个显示器或将当前显示器连接到另一台计算机来检查显示器是否存在问题。如果问题仍然存在,那么您可以排除显示器故障的可能性。 二、显卡问题如果您的电脑配备了独立显卡,那么显卡故障也可能是导致电脑
plsql连接Oracle超时,完犊子了肯定是服务器断电了。得马上检查Oracle服务器状态1、检查数据库是否启动su-oracle切换到Oracle用户,输入sqlplus/assysdba显示连接状态。如果末尾显示的状态是Connectedtoanidleinstance.证明未启动2、启动数据库startup启动数据库,末尾出现Databaseopened说明数据库启动成功3、查看数据库监听是否正常先quit;断开Oracle连接,使用lsnrctlstatus查看监听状态,如果出现TNS-开头的Nolistener、Connectionrefused等错误,说明监听未启动4、启动数据库