【iOS】アプリ起動時間の最適化及び計測方法
アプリが立ち上がり使用できるようになるまでの時間をどのようにすれば最適化できるかというセッションでWWDC2016でAppleがOptimizing App Startup Time
という動画がでている。聞いた限りここで紹介されている内容は2017年現在でも変わらず有効なように聞こえる。
ここではdyldなどの動的なローダの内部的な詳細などについてやアプリの起動時間の最適化に関するベストプラクティスが述べられている。
さて、まずはじめに、どのようにアプリの起動時間を計測して、なにを基準に最適化を目指すかという問題がある。
これについてAppleは起動時間については400ms
未満で立ち上がることを推奨している。(アプリの起動時間をテストするときには、できるだけ性能の高いデバイスを基準として計測すること)
では、どのように起動時間を計測するかというと、XCode付属のTime Profiler
とXCode
の環境変数を使うことでアプリの起動時間とそれに寄与しているステップを把握することができる。
まずTime Profiler
ではアプリの初期化時間、起動時間、ボトルネックとなっている関数の割り出しなどが可能で、100000分の1秒単位で計測できる。
使い方はXCode
のメニューからInstrument
を開きTime Profiler
を選択する。
起動後は再生ボタン横のところで端末とアプリを選択して再生をすると、自動で当該アプリが起動されLife Cycle
というグラフ上にInitializing
とLaunching
という計測時間結果が表示される。
Initializing
はアプリを起動するまでに行われるPre-Main time
や依存関係のロードの時間を表し、Launching
はアプリ自体を立ち上げるために掛かった時間を表している。つまりユーザがアプリアイコンをタップしてからアプリを使えるようになるまでの起動時間はInitializing
+Launching
の値ということになる。
ほとんどの場合Initializing
の時間のほうが掛かってしまうが、これはアプリを起動するために必要なフレームワークなどの依存関係の読み込みが全てこのステップで行われるからであり、Carthage
やCocoapods
等を全く使用していないアプリにおいても内部で使用されている標準フレームワークのロードなどが行われる。
では一番起動時間に関わっている動的ローディングの部分は実際にどのくらい時間がかかっているかを計測する方法もある。それはXCodeの環境変数でDYLD_PRINT_STATISTICS
を追加することで取得できる。
[出力例]
Total pre-main time: 56.23 milliseconds (100.0%) dylib loading time: 37.23 milliseconds (66.2%) rebase/binding time: 6.81 milliseconds (12.1%) ObjC setup time: 8.16 milliseconds (14.5%) initializer time: 13.19 milliseconds (23.4%) slowest intializers : libSystem.dylib : 5.22 milliseconds (9.2%)
このようにdylib
のロード時間が最も起動時間に寄与していることがわかる。
では、次にこのdylib
のロード時間を短縮・最適化する方法については、Appleは以下のことを推奨している。
Appleのシステムフレームワークの読み込みは高度に最適化されているが、
組み込みフレームワーク
は時間が掛かってしまう。そのためdylib
の読み込み時間を減らす方法は、いくつかの組み込みフレームワークを合併させるか、そもそも組み込みフレームワーク
を減らすという手段がある。また、非システムフレームワークでは多くても6個までが良いとされている。多数のObjective-Cクラスやセレクターなどは起動時間を遅くする(SwiftのStructなどは高速)
ObjcのついているものはObjective-Cのランタイムが必要ということでクラス・カテゴリの登録や使用するセレクターの一意化が必要となり、リベース/バインディングのステップで時間がかかるため、
Objc
を減らすことでも起動時間の短縮に繋がる。
参考: