iOS Mail Mail.Ruの例でのiOSアプリケーションのクイックスタート





ニコライ・モレフ( Mail.Ru



今日は、アプリケーションの起動時間を短縮した経験と、彼が教えてくれたことについてお話します。



ここで、ほとんどのユーザーの場合、起動時間は約4秒で、さらに少し長くなっています。 したがって、最近、新しい機能ではなく、製品の品質にもっと注意を払うことにしました。 テストの範囲を拡大し始め、アプリケーションのサイズを縮小し、起動速度を最適化し、ネットワークリソースの使用を最適化することに取り組み始めました。 これが私たちが学んだことです。



私たちのアプリケーションは、mail.ruで設定されたメールボックスだけでなく、あらゆるメールボックスを操作できる電子メールクライアントです。 また、アプリケーション開発の歴史はもう少し長く、Agent Mail.Ruアプリケーションに根ざしていますが、2012年からストアにいます。



ほぼすべての時間で、私たちはロシアのストアで最も人気のある無料アプリケーションのランキングで30位に、パフォーマンスセクションで1-2位にいます。 今日はパフォーマンスについても説明しますが、それについては詳しく説明しません。 国際的な視聴者向けに、MyMailと呼ばれるわずかに異なるデザインの同じアプリケーションを作成しています。 そして、ユーザーは時々これに気づきます。







今日は、アプリケーションの起動時間を短縮した経験と、彼が教えてくれたことについてお話します。





ユーザーは、原則として、アプリケーションに関するいくつかの問題を常に指摘し、ユーザーにとって本当に重要なことについて話します。 AppStoreのサンプルレビューは次のとおりです。







さらに、当社が収集した分析データにより、起動時間に関する問題も確認されました。







ここで、ほとんどのユーザーの場合、起動時間は約4秒で、さらに少し長くなっています。 したがって、最近、新しい機能ではなく、製品の品質にもっと注意を払うことにしました。 テストの範囲を拡大し始め、アプリケーションのサイズの縮小、起動速度の最適化、ネットワークリソースの使用の最適化に取り組み始めました。



まず、この問題の緊急性にどのようになったのか見てみましょう。 起動速度の問題が私たちを心配し始めたのはどうしてですか。 おそらく、これらの要因をアプリケーションと比較して理解することはできますが、一般的には行う価値がありますか?







まず最初に、アプリケーションにはユースケースがあり、ユーザーが1日の間に何度も起動するということがあります。 そしてもちろん、同時にアプリケーションの起動が遅いと、誰もがイライラします。



2番目の理由は、開発中の非常に多くの質問に対する明白な答えです。「これが歴史的にどのように起こったかです。」 パフォーマンスの問題は、技術的負債と呼ばれる問題に起因すると考えられます。 これらの問題は、新しい機能が目に見えないようにすべての人に追加されるにつれて徐々に蓄積され、意図的にでも開発時間を短縮することが起こります。 誰もがこれらの状況を知っていると思います。 このため、アプリケーションがそれほど頻繁に起動されない場合、起動速度を最適化することはほとんど意味がありません。



もう1つの理由は、継続的なパフォーマンス監視の欠如です。 技術的な負債を累積するプロセスは、ご存じのとおり、自然であり、起動コードに影響を与える可能性のある新しいコードが常にアプリケーションに追加されています。 このコードの一部は、開始プロセスで実際に実行する必要があります。これらは、ロギングライブラリのセットアップ、キャッシュをキャッチするためのライブラリの起動などです。 そして、判明した部分は、ランダムに起動プロセスに追加されます。 監督によって。 たとえば、アプリケーションの最初の段階では、非常に歴史的に見て、アプリケーションのすべての画面の外観をカスタマイズします(最初に直接表示されない場合でも)。



このすべては、開始時間が非常にわずかに増加するたびに複雑になります。 また、この劣化は手動テストでは確認できません。また、プロファイラーなどの特別なツールを使用しても、プロファイラーの変更のエラーは行われた劣化よりも大きいため、この劣化に気付かない場合があります。







ここに、ここ数か月で構築した起動速度のグラフを示します。 これは、この問題を正確に示しています。少しずつ、起動速度が増加し、新しいコミットごとに増加しています。 このグラフは、起動速度を改善するための作業の結果の1つでした。次に、アプリケーション用にこのようなグラフを作成する方法を説明します。







しかし、最初に、起動速度を改善するための作業プロセスを構築する方法について話しましょう。



誰もが、最適化の主なルールである早すぎる最適化がすべての悪の根源であることを知っています。 したがって、開始する前に、主な質問を決定する必要があります-正確に最適化するもの、ユーザーが最適化の効果をどのように感じるか、変更が目標につながったかどうかをどのように理解するか、そして一般に、最初に確認するのが良いでしょう最適化が可能かどうか、および起動速度を改善できる最大値は何ですか?速度はコードだけでなく、影響を与えられない外部要因にも依存する可能性があるためです。 これらの質問に答え始めましょう。



何を最適化しましたか? 最適化のために最も一般的なスタートアップシナリオを選択しました。 これは、アプリケーションがメモリからアンロードされ、ユーザーがすでにアカウントにログインしており、起動時にInboxフォルダー内の文字のリストに到達したときです。 次のようになります。







次。 ユーザーが感じるはずの効果。







すべての最適化の結果、ユーザーは開始時にブレーキの感覚を失うはずです。 これを達成するために、私たちは2つの側面から取り組みます-時間自体を短縮しようとしますが、さらに、開始時間の主観的な認識を改善しようとします。



ここでは、技術的な部分、つまり時間をどのように改善したかについてのみ説明しますが、私の記事のリンク(後で説明します)には、主観的な知覚を改善するためのいくつかの方法があります。



次。 最適化が効果をもたらしたことを測定する方法は?







最適化に取り組む過程で、最適化できる場所を見つけようとする過程で、Time Profilerを使用しました。 変更の全体的な効果を評価するために、アプリケーションに組み込まれたログを使用しました。 Time Profilerを使用しなかったのはなぜですか? アプリケーションの小さな部分を切り取り、最適化し、いくつかのコードを削除した場合、これが全体の開始時間に影響するという事実からはほど遠いためです。 そして、もちろん、測定を可能な限り有効にするために、私たちが持っている最も遅いデバイスですべての測定を行います。シミュレータではありません。







そして、最後の質問への答え-原則として、最適化の限界は何ですか-私たちは次のようになりました。 文字通り、Xcodeのシングルビューアプリケーションテンプレートである最小限の機能を備えたシンプルなテストアプリケーションを作成し、ヘッダー、文字のリスト、および文字のリストを模倣するいくつかのセルを含む画面を追加しました。 また、このアプリケーションでは、原則として最適化できない時間を測定しました。 そして、理論的には2秒程度で最適化の機会があることに気付きました。



最適化に直接進みます。 打ち上げの最初のフェーズから始めましょう。







最初の段階は、アプリケーションアイコンをクリックしてから制御を独自のコードに移すまでの時間です。 実際、この段階では多くのことが起こっており、具体的な時間がかかるかもしれません。







悪いニュースは、最初の段階ではプロファイラーにほとんどデータが表示されないことですが、良いニュースは今回も影響を与える機会がまだあることです。







今年のWWDCでは、第1段階に関する優れたレポートがあり、ここで何が起こっているのかを詳細に検討し、それについて何ができるかについての推奨事項が提示されました。



ここで何が起こっていますか? iOSは、アプリケーションの実行可能コードをメモリにロードし、必要な操作、アプリケーション内にあるインジケーターのシフトを実行します。 ポインタを外部ライブラリにバインドし、すべての実行可能ファイルの署名をチェックしてから、メソッドをロードし、静的コンストラクターが実行されます。 これは、オペレーティングシステムのコードではなく、すでに私たちのコードである最初のコードです。 例として、アプリケーションでどのように見えるか、さまざまな段階でどのように分類されるかを図で示しました。 アプリケーションでは、XcodeのDYLD_PRINT_STATISTICS環境変数を使用して同じデータを取得できます。 したがって、最初の段階を高速化するための主な推奨事項は、これらの段階を減らすことです。 これを行う方法?







WWDCのレポートからスライドを切り取りました。これは、すべての推奨事項を簡潔にまとめたものです。アプリケーションを高速に動作させるには、アプリケーションで行う操作を少なくするだけです。



他にどのような推奨事項がありますか?







アプリケーションにある動的フレームワークの数を減らします。 なんで? システムフレームワークよりも読み込みが非常に遅いため、システムダイナミックフレームワークのロードはオペレーティングシステムで事前に最適化されており、ネイティブダイナミックフレームワークの最適数として5が指定されています。



このアプリケーションには、動的フレームワークが1つしかありません。主に、異なるアクションの間にコードを埋め込み、このコードが重複しないようにアプリケーションのサイズを小さくするために追加しました。 しかし、原則として、起動速度のみを考えた場合、動的フレームワークを拒否できます。



ところで、swiftを使用すると、すぐに独自の動的フレームワークがいくつか追加されますが、これらもこの制限内にあると見なされます。 つまり swiftを使用すると、起動時に特定のオーバーヘッドが追加されます。



リベース修正、バインディング修正としてマークされているステップは、アプリケーションのObjective-C文字の数の影響を受けるため、ここでの主な推奨事項は、大きなクラスを作成し、大きなメソッドを作成することでした。 または、すべてのアドレスが静的に設定され、これらの手順を実行する必要がないか、少なくとも短縮されている、迅速に切り替えます。



当然、既存の大規模なアプリケーションの場合、これはあまり有用な推奨事項ではありません。多くのリファクタリングを行い、大量のコードを再テストする必要があり、一般に、コードの可読性はもちろん低下します。 したがって、新しいアプリケーションであっても、この最適化方法はお勧めしません。







第二段階、すでにオペレーティングシステムから制御を得たとき。 ここでは、コードを何らかの方法で変更できるため、アクションの余地がすでにあります。当然、ここでの研究のために、Time Profilerの使用を開始しました。 Time Profilerについては説明しません。







Time Profilerは非常にクールで強力なツールであり、非常に役立ちましたが、ここでは解決できないいくつかの問題または欠点をリストします。



ところで、高負荷システムHighLoad ++の開発者の会議の過去5年間の公開ビデオを公開しました。 YouTubeチャンネルを視聴、学習、共有、購読します


まず、アプリケーションで明らかなボトルネックを見つけることができなかったため、すぐに改善できました。 これは、「均一に遅いコード」と呼ばれるよく知られた開発上の問題であり、最初に適切で読みやすいコードを作成しようとするときの最適なアプローチの結果です。 この問題の別の理由は、使用されているプラ​​ットフォームの機能そのものです。 たとえば、Objective-Cメソッドを呼び出すオーバーヘッドにはかなり時間がかかることがわかります。







2番目の問題は、タイムプロファイラーです。 場合によっては、Time Profilerではコールツリーのそのような重い部分を見ることができますが、問題は、特定のコールがどのビューからアプリケーションのどの部分に属しているかを常に理解できるとは限らないことです。 これは主に、レイアウトを分析するとき、またはXIBからビューをロードするときに観察されます。 XIBにはかなり複雑な階層を持たせることもでき、どのビューがそこにゆっくりと読み込まれているかは必ずしも明確ではありません。







次の問題は、CPU使用率グラフの低下です。 理想的には、もちろん、すべてが非常に迅速に機能するためには、メインスレッドが常に100%でロードされ、そこで何かが常に実行される必要があります。 しかし、チャートでは常にディップが見られます。ディップは小さくても大きくてもかまいません。TimeProfilerは、それらが生じる理由についてほとんど何も教えていないので、それがそれらにつながります。 ただし、主な理由は2つあります。







タイムプロファイラーのもう1つの問題は、既に前述したとおり、測定値の広がりが非常に大きくなる可能性があるため、最適化の一般的な効果を理解することが難しいことです。 これは同じアプリケーションで何も変更せずに測定を行ったもので、開始から開始までの時間は非常に異なることがわかります。







最適化する場所を探すとき、他に何を探すことができますか?







プロファイラーは多くの有用な情報を提供してくれますが、私たちの心理学は間違った道をたどりやすいように設計されています。 分析中、私たちは本当に時間がかかり、大きな利益を得ることができる場所ではなく、私たちが非常に簡単に気づきやすく理解しやすい場所に興味を持っている場所にもっと注意を払う傾向があります。



たとえば、最適化の場所を見つけるプロセスで、起動段階でベースボードへの呼び出しが20ミリ秒かかった場所を見つけました。 私は考え始めています:「どうすればこれらすべてを取り除くことができますか? たぶん、ベースボードを別のものに置き換えますか?」 しかし、良い方法では、1レベル上の問題を見て、なぜこれを行っているのかを原則的に理解する必要があります。 私たちの場合、これはアプリケーションの起動に関する統計を送信するプロセスで行われ、原則として、この統計の送信を少し後の段階に単純に転送することができ、これから機能的にほとんど変化しません。



当然、主にメインスレッドの作業量を減らしたいと考えています。 まず第一に注意を払っていますが、ハードウェアを並列化する可能性は無限ではないため、バックグラウンドスレッドについても忘れてはなりません。 特に、最初に使用して初期化したライブラリの1つがすぐにバックグラウンドスレッドに入り、そこで作業を行うという状況に直面しました。 最初は、彼女がそこで何をしていたかさえ見ていませんでしたが、その後、それをオフにして何が起こるかを見ることにしました。 そして、これはかなり大きな効果をもたらしました。



Time Profilerに戻ると、そもそもほとんどの時間がUIとレイアウトのレンダリングに費やされているのが印象的です。 しかし、分かりにくい、CA、レンダリングなどの奇妙なシステムコールがいくつかあるため、今回のUIで正確に何が費やされるかは、トレースから常に明確ではありません。 また、これらの呼び出しは、画面上のあらゆるレンダリングを参照できます。 しかし、実際には、ラベルをディスクから読み取ってデコードする必要があるため、サイズと描画、および画像の計算が比較的困難であるため、UIで最も貪欲なのはラベルのレンダリングです。



上記のすべてから結論が得られます-起動時間を短縮したい場合は、すべての操作を可能な限り遅延させてください。 これはどういう意味ですか? 画面またはビューが開始直後に表示されない場合は、それらを作成または構成しないでください。 一般に、これはおそらく明らかなボトルネックがない既存の大規模アプリケーションを高速化する最も効果的な方法です。



たとえば、アプリケーションで何を怠zyにしましたか? セカンダリスクリーンの外観を設定するプロセスで、写真の遅延読み込みを行いました。 中間起動画面を削除し、サイドメニューにあるバックグラウンド画面の作成を削除しました。 原則として、このルールはUIだけでなく、アプリケーションの起動時に何らかのマネージャーまたはアクションを初期化する必要がある場合、ロジック、コードにも適用されます。 メインユーザーインターフェイスが表示されたときに延期できるかどうかを検討します。 おそらく機能性の面で違いはありません。







また、ビルダーインターフェースまたはコードでUIを作成するなど、物議を醸すトピックに関するいくつかの言葉。 奇妙なことに、XIBは通常は問題ではありません。コード内の同様のUIの作成は非常にわずかに速く実行されますが、

さらに遅い場合。 以下は、この比較が行われたかなり古いブログ投稿へのリンクです。 必要に応じて、テストプロジェクトをダウンロードできますが、2010年に作成されているため、Xcodeの最新バージョンにドラッグするには多少の労力がかかります。 そして、何が遅いのか、何が速いのかを自分で確認できます。







入出力。 原則として、最新のデバイスのフラッシュメモリへの読み取りと書き込みは非常に高速です。これらは単位または数十ミリ秒です。したがって、これに悩む価値は必ずしもありませんが、起動時にサードパーティのコードが誤用し、多くのファイルを開くことがあります。 たとえば、Flurry分析フレームワークと、アプリケーションの外観をカスタマイズするために写真をアップロードする独自のコードでこのような問題を発見しました。 タイムプロファイラーはそのような場所を表示しません。 Time Profilerでは、せいぜいCPUグラフにわずかな低下が見られるだけです。 代わりに、別のツール-I / Oアクティビティを使用できます。これは、すべてのI / Oと対応するファイルの名前をリストします。 名前によって、このファイルがアプリケーションのどの部分を読んでいるかを判断するのは非常に簡単です。



I / O Activityツールだけでなく、open関数の簡単なブレークポイントでも同様の情報を取得できます。 先ほどお話ししたシステムフレームワークとXPCの場合、CPUグラフのエラーに注意を払うことで追跡できます。 Profiler' Call Samples, -, , . , .







Time Profiler … layout, swizzling' layoutSubviews . swizzling . Objective-C . -swizzling' layoutSubviews – , , layout . , , Google Sheets, . , , , , layout'.







, , – , , . callback' .. , - - , , , - . , , . , - , .



, Time Profiler , .. , , , . , . :







. . , Time Profiler. , . , Time Profailer. Google Sheets, :







, , .







つまり , - , , .



, :







, , ..



.







Continuous Integration, TDD , - , . . , . , , … , , , . . , - , .



, , , , . , .



, .







Jenkins. , , . 270 . Iphone 5S, iOS 9.



, , , 270? , , , . 10 . 10 . - .



, , , 10 270 . , , , .



, 270 , , InfluxDB, .



, , . , bash- 10 . , .







, iOS – , , , , , . USB-, Apple , Jailbreak ssh . , , , , . , USB. , Jenkins . , - , .



, :







, , - , , , , . - - – - -, .



, , , , - Profiler, . , - , run time , - Time Profiler div, , , .



, - - , .



, , .











, . ( ).







2 . , . , . -, , .. , , . , , , , « » , 30% .







, , , 2 , 10 . , 10 , ? , 40%, Time Profiler.



, – – . :







.







, , .



, , .







github

twitter



このレポートは、負荷の高いシステムHighload ++の開発者の専門家会議での最高のスピーチの1つ、具体的には「モバイルアプリケーションのパフォーマンス」セクションの転写です



数週間で、モバイル開発

専用の会議-AppsConfが開催されます。ここで、Yandexは Yandex.Mapsの例で読み込み時間の最適化について説明します。Mail.ruチームは、ICQの例を使用して、今回はiOSアプリケーションのサイズを最適化するトピックを明らかにします



All Articles