Android パフォーマンスの最適化 - 起動の最適化

アプリの起動速度はユーザーの最初の体験です。インターネットには 8 秒ルールがあり、アプリが開くまで 8 秒待つと、70% のユーザーが待つのをやめます。

 1. 分類を開始する

公式アプリの起動時間 

  • コールドスタート

         最も時間のかかる測定基準

  • ホットスタート

         最速。バックステージ〜フロントステージ

  • ウォームスタート

         もっと早く。アクティビティのライフサイクルのみが繰り返されますが、プロセスの作成やアプリケーションの作成とライフサイクルは繰り返されません。

コールドスタートプロセス

  1. ユーザーのクリック数 
  2. IPC動作のトリガー
  3. Process.startプロセスの作成
  4. ActivityThread は個別のプロセスへの入り口であり、メッセージ ループとハンドラーを作成するメイン メソッドがあります。
  5. bindApplication はリフレクションを通じてアプリケーションを作成し、アプリケーションのライフサイクルを呼び出します。
  6. アクティビティのライフサイクル 
  7. ViewRootImpl は実際のインターフェイスの描画を開始します

コールドスタート前 (このプロセスは介入できません)

  • アプリを起動する 
  • 空のウィンドウをロードする 
  • プロセスの作成

後続のタスク

  • アプリケーションの作成 
  • メインスレッドを開始します
  • メインアクティビティの作成 
  • ロードレイアウト
  • レイアウト画面
  • 最初に描かれたフレーム


        アプリケーションとアクティビティのライフサイクルを最適化する

2. 起動時間の計測方法

adbコマンドモード

        adb shell am start -W パッケージ名/首屏Activity 

    特徴:

  • オフラインでは簡単に使用できますが、オンラインにはできません
  • 厳密ではない正確な時間

手動マーキング方法では、
        開始時にポイントを埋め込み、開始時と終了時にポイントを埋め込みます。2 つの
     機能の違いは次のとおりです。       

         正確、オンライン化可能、使用推奨

     誤解を避ける

  • 起動時間の開始点はアプリケーションのattachBaseContext内にあります 
  • 開始時間の終了位置はフィードの最初の表示を採用します。
  • addOnDrawListener には API 16 が必要です

ThisTime 最後のアクティビティの開始にかかった時間
TotalTime すべてのアクティビティの開始にかかった時間
WaitTime AMS アクティビティの開始にかかった合計時間

3. 最適化に使用するツールを起動します

 トレースビュー、systrace 

  • 両方のツールは相互に補完します
  • ツールを正しく理解し、さまざまなシナリオに適したツールを選択する

トレースビュー

  • アドバンテージ
    •  コードの実行時間、コールスタック情報などを示すグラフィカルフォーム。
    • すべてのスレッド情報を含む包括的な情報
  •  使用法

      Debug.startMethodTracing("ファイル名"); デフォルトのサイズは 8M です。より大きなサイズが必要な場合は、パラメータ BufferSize を渡します 
      。Debug.stopMethodTracing() は
      、SD カードの最後にファイルを生成します: Android/data/packagename /ファイル

Android Studio の右側に Devices File Explorer があり、携帯電話システムのファイルを簡単に開くことができます。
開始コードと終了コードを追加した後、実行し、保存場所の下で更新し、ファイル名を設定します.trace ファイルが生成されます。

  • 分析方法
    • 左上はコードで正確に指定された時間範囲で、左下隅には特に重要ではない時間が表示されています。
    • 左下はスレッド情報で、スレッドの総数と各スレッドが特定の時間に何をしたかを確認できます。 

右側にタブが4つあります 

  • トップダウン

合計: 合計時間

自分自身:

子供たち:

例: 関数 A が呼び出され、全体の時間が合計され、関数 A でコード行が呼び出され、次に関数 B が実行されます。その selfTime はコード行が実行された時間、childrenTime は実行された時間です。関数 B が実行されます。selfTime と ChildrenTime の合計は totalTime と等しくなければなりません

関数呼び出しリストで、対応するソースへのジャンプをクリックして詳細なコードにジャンプします

ThreadTime は確実に短くなります。CPU の実行時間です。
Wall Clock Timeコードがこのスレッド上で発生し、実際の実行時間です。

  • 通話チャット 

各行は関数呼び出しの期間を示し、垂直メソッドが呼び出されます。
システム API 呼び出しの色はオレンジ、
アプリケーション自身の関数呼び出しの色は緑、
サードパーティ API 呼び出しの色は青です。

  • フレームチャットフレームグラフ

同じ呼び出しシーケンスを収集する反転呼び出しグラフ

  • ボトムアップ

誰が私に電話をかけたかはトップダウンの逆です

概要:
        実行時のオーバーヘッドが深刻で、全体の速度が低下します。このツールは強力すぎるため、すべてのスレッドのすべての実行関数をキャプチャし、その順序によって最適化の
        方向が偏る可能性があります。traceview
        と CPU プロファイラ の
                traceview の利点は次のとおりです。 CPU プロファイラー分析を使用する
                CPU プロファイラーを使用して正確な起動場所をキャプチャすることは、ほとんど不可能です。

 システムレース

Android カーネル データを結合して HTML レポート
Python スクリプトを生成する

  • 使用法

• python systrace.py -t 10 [その他のオプション] [カテゴリ]

  • 公式ドキュメント:

https://developer.android.com/studio/command-line/systrace#command_options

  • 使用例

python /Users/Liuzhao.Future/Library/Android/sdk/platform-tools/ systrace/systrace.py -b 32768 -t 5 -a com.optimize.performance -o パフォーマンス。html sched gf view wm am app

  • コードで使用される

開く: TraceCompat.beginSection(“apponCreate”)
終了: TraceCompat.endSection 

  • HTMLファイルを分析する

CPU コアの数は携帯電話によって異なります。一部の携帯電話メーカーは 8 コアを提供しますが、一部の携帯電話は 8 コアを搭載していますが、実際に使用されるのは 4 コアのみです。

  • 要約:
    • 軽量でオーバーヘッドが低く、やりたいことを何でも実行できます
    • CPU使用率を直感的に反映

CPUTime と WallTime

  • WallTime はコードが実行された時間です
  • cpuTime はコードが CPU を消費する時間です (主要なインジケーター)

例: なぜ 2 つのロックには異なる
        ロック競合が発生するのでしょうか? たとえば、スレッドは実行のためにロック A を取得する必要がありますが、ロック A は他のスレッドによって保持されており、解放されていません。ただし、このスレッドは軽量であり、少ししか占有しません。したがって、この時点では、cpuTime は非常に短く、wallTime は非常に長くなります。

4. CPU 消費時間を効率的に取得する方法

どの方法が最も時間を費やしているかを知る必要がある

  • 従来工法:手動埋設ポイント
    • 非常に侵襲的
    • 重い作業負荷
  • AOP メソッド: アスペクト指向プログラミング、アスペクト指向プログラミング
    • 同じ種類の問題に対する統一的な処理
    • 侵入せずにコードを追加

アスペクトの使用

  • クラスパス「com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0」
  • 実装「org.aspectjaspectjrt:1.8.+」
  • プラグインを適用: 'android-aspectix'

導入

  • 参加ポイント
    • プログラム実行時の実行ポイントは、アスペクトの場所として使用できます。
    • 関数呼び出し、実行
    • 変数の取得と設定
    • クラスの初期化
  • ポイントカット
    • 条件付きの JoinPoint
  • アドバイス
    • コードが挿入されるフックの一種
    • Before: PointCut の前に実行
    • 変更後:PointCut 後に実行
    • 前後:ポイントカットの前後で別々に実行
  • 文法入門
    //Before:Advice,具体插入位置
    //execution :处理Join Point的类型
    //(* android.app.Activity.on**(.)):匹配规则
    @Before("execution(* android.app.Activity.on** (.))") 
    public void onActivityCalled (JoinPoint joinPoint) thr
    ows Throwable {
        ……
    }
  • 使用例
@Aspect
public class Performanceaop{

    Around("call(*com.optimize.performance.PerformanceApp.**(..))") 
    public void getTime(ProceedingJoinPointjoinPoint){
        Signature signature=joinPoint.getSignature(); 
        String name=signaturetoShortString(); 
        long time=System.currentTimeMillis(); 
        try {
            joinPoint.proceed();
        } catch(Throwable throwable){
            throwable.printStackTrace();
        }
        LogUtils.i(msg:name+" cost "+(System.currentTimeMillis() - time));
    }
}
  • アドバンテージ
    • 非侵襲的
    • 変更が簡単

5. 非同期の最適化

  • 一般的な非同期最適化: 非同期最適化のためのスレッド プールの使用
  • ランチャー (非同期起動最適化の最適なソリューション)

通常の非同期モード

従来の非同期メソッドに関する注意事項:

  • すべてのコードを直接非同期にできるわけではありません
  1. 非同期要件を満たしていません: 一部のタスクはメインスレッドで実行する必要があります
  2. 特定の段階で完了する必要があります。非同期タスクはスプラッシュ インターフェイスで使用されます。インターフェイスを実行するとき、非同期タスクが完了する前に、一部のコードが特定の段階で完了する必要があります。解決策: CountDownLatch はロックを追加するのと同じです。
  3. CPU 集中型タスクと IO 集中型タスクを区別する

従来の非同期ソリューションの問題点:

  • コードが十分にエレガントではない
  • シーンの処理が難しい (依存関係)、特定の時間内にタスクを終了する
  • 高額なメンテナンス費用

ランチャーモード

コアアイデア:
     CPUマルチコアを駆使し、タスクシーケンスを自動で振り分ける
ランチャープロセス:

  • コードはタスク指向であり、起動ロジックはタスクに抽象化されています。 
  • すべてのタスクの依存関係に基づいて有向非巡回グラフを生成します。
  • マルチスレッドはソートされた優先度に従って順番に実行されます。

6. 初期化の遅延

  • 一般的な解決策: handler.postDelay 
  • より良い解決策: 遅延したタスクをバッチで初期化する

従来のソリューションの問題点:

  • タイミングをコントロールするのが難しい
  • 送り遅れの原因

より良いソリューションの利点: IdleHandler 機能を利用し、アイドル実行

  • 実行時間が明確
  • フィードラグを軽減する

7. 概要: 最適化の一般的なポリシーを開始する

  • 非同期、遅延、遅延読み込み
  • テクノロジーとビジネスの融合

8. 注意事項

  • Convergence スタートアップ コードの変更権限
  • Ci と組み合わせてスタートアップ コードを変更するにはレビューまたは通知が必要です

9. その他のオプション

  • 事前に SharedPreference をロードする 

        multidex の前にロードし、このステージを最大限に活用すると、CPU は 
        getApplicationContext を上書きしてこれを返します。

  • 起動中に子プロセスを起動しない

        子プロセスは CPU リソースを共有するため、メイン プロセスの CPU に負担がかかります。
         起動シーケンスに注意してください。App onCreate の前に ContentProvider が配置されます。 

  • クラスロードの最適化、事前の非同期クラスロード
  • 起動フェーズ中の GC を抑制する 
  • CPU周波数ロック

おすすめ

転載: blog.csdn.net/weixin_42277946/article/details/131808262