次の方法で共有


アプリ起動時のパフォーマンスのベスト プラクティス

起動とアクティブ化の処理方法を改善することで、最適な起動時間でユニバーサル Windows プラットフォーム (UWP) アプリを作成します。

アプリ起動時のパフォーマンスのベスト プラクティス

一部では、アプリの起動にかかる時間に基づいて、アプリの速度が速いか遅いかをユーザーが認識します。 このトピックの目的上、アプリの起動時間は、ユーザーがアプリを起動したときに開始され、ユーザーが何らかの意味のある方法でアプリを操作できる時点で終了します。 このセクションでは、起動時にアプリのパフォーマンスを向上させる方法について説明します。

アプリの起動時間の測定

実際に起動時間を測定する前に、アプリを数回起動してください。 これにより、測定のベースラインが得られ、できるだけ短い起動時間で測定できるようになります。

UWP アプリが顧客のコンピューターに到着する頃には、アプリは .NET ネイティブ ツールチェーンを使用してコンパイルされています。 .NET Native は、MSIL をネイティブで実行可能なマシン コードに変換する、事前コンパイル テクノロジです。 .NET ネイティブ アプリは、起動速度が速く、使用するメモリが少なくなり、MSIL に対応するアプリよりも使用するバッテリーが少なくなります。 .NET ネイティブを使用して構築されたアプリケーションは、カスタム ランタイムと、すべてのデバイスで実行できる新しい集約型 .NET Core に静的にリンクされるため、インボックスの .NET 実装に依存しません。 開発用コンピューターでは、"リリース" モードでビルドする場合は既定で .NET Native が使用され、"デバッグ" モードでビルドする場合は CoreCLR が使用されます。 これは、Visual Studio の [ビルド] ページの [プロパティ] (C#) または [マイ プロジェクト] (VB) の Compile->Advanced から構成できます。 ".NET ネイティブ ツールチェーンを使用してコンパイルする" というチェック ボックスを探します。

もちろん、エンド ユーザーが経験する内容を代表する測定を行う必要があります。 そのため、開発用コンピューター上のネイティブ コードにアプリをコンパイルしているかわからない場合は、起動時間を測定する前にネイティブ イメージ ジェネレーター (Ngen.exe) ツールを実行してアプリをプリコンパイルできます。

次の手順では、Ngen.exe を実行してアプリをプリコンパイルする方法について説明します。

Ngen.exe を実行するには

  1. アプリが Ngen.exe に検出されるように、少なくとも1回起動してください。

  2. 次のいずれかの操作を行って 、タスク スケジューラ を開きます。

    • スタート画面から「タスクスケジューラ」を検索します。
    • "taskschd.msc" を実行します。
  3. タスク スケジューラの左ペインで、タスク スケジューラ ライブラリを展開します。

  4. Microsoftを展開する。

  5. Windows を展開します。

  6. の .NET Frameworkを選択します。

  7. タスクリストから.NET Framework NGEN 4.xを選択します。

    64 ビット コンピューターを使用している場合は、 .NET Framework NGEN v4.x 64 もあります。 64 ビット アプリをビルドする場合は、 を選択します。NET Framework NGEN v4.x 64

  8. [アクション] メニューの [実行]をクリックします。

Ngen.exe は、使用されていてネイティブ イメージがないコンピューター上のすべてのアプリをプリコンパイルします。 プリコンパイルが必要なアプリが多数ある場合、これには時間がかかる可能性がありますが、後続の実行ははるかに高速です。

アプリを再コンパイルすると、ネイティブ イメージは使用されなくなります。 代わりに、アプリは Just-In-Time コンパイルされます。つまり、アプリの実行時にコンパイルされます。 新しいネイティブ イメージを取得するには、Ngen.exe を再実行する必要があります。

可能な限り作業を延期する

アプリの起動時間を短縮するには、ユーザーがアプリの操作を開始するために絶対に必要な作業のみを行います。 これは、追加のアセンブリの読み込みを遅らせることができる場合に特に便利です。 共通言語ランタイムは、初めて使用されるときにアセンブリを読み込みます。 読み込まれるアセンブリの数を最小限に抑えることができる場合は、アプリの起動時間とそのメモリ消費量を向上させることができます。

長時間実行される作業を独立して行う

アプリの一部が完全に機能していない場合でも、アプリを対話型にすることができます。 たとえば、取得に時間がかかるデータがアプリに表示される場合は、非同期的にデータを取得することで、そのコードをアプリのスタートアップ コードとは別に実行できます。 データが使用可能になったら、アプリのユーザー インターフェイスにデータを設定します。

データを取得するユニバーサル Windows プラットフォーム (UWP) API の多くは非同期であるため、おそらく非同期的にデータを取得することになります。 非同期 API の詳細については、「 C# または Visual Basic での非同期 API の呼び出し」を参照してください。 非同期 API を使用しない作業を行う場合は、ユーザーがアプリを操作できないように、Task クラスを使用して実行時間の長い作業を実行できます。 これにより、データの読み込み中にユーザーに対するアプリの応答性が維持されます。

アプリが UI の一部を読み込むのに特に時間がかかる場合は、アプリがまだ処理されていることをユーザーが認識できるように、"最新のデータを取得する" などの文字列をその領域に追加することを検討してください。

起動時間を最小限に抑える

最も単純なアプリ以外はすべて、リソースの読み込み、XAML の解析、データ構造の設定、アクティブ化時のロジックの実行に、目に見える時間が必要です。 ここでは、アクティブ化のプロセスを 3 つのフェーズに分割して分析します。 また、各フェーズで費やされる時間を短縮するためのヒントや、アプリのスタートアップの各フェーズをユーザーにとってよりわかりやすいものにするための手法も提供します。

アクティブ化期間は、ユーザーがアプリを起動してからアプリが機能するまでの時間です。 これは、アプリに対するユーザーの第一印象であるため、重要な時期です。 システムとアプリからの即時かつ継続的なフィードバックが期待されます。 アプリがすぐに起動しない場合、システムとアプリは壊れているか、設計が不十分であると認識されます。 さらに悪いことに、アプリのアクティブ化に時間がかかりすぎる場合、プロセス ライフタイム マネージャー (PLM) によってアプリが強制終了されたり、ユーザーがアプリをアンインストールしたりする可能性があります。

スタートアップのステージの概要

スタートアップには多数の移動要素が含まれます。最適なユーザー エクスペリエンスを得るために、それらのすべてが正しく調整されている必要があります。 次の手順は、ユーザーがアプリ タイルをクリックしてから、表示されるアプリケーション コンテンツの間で発生します。

  • Windows シェルがプロセスを開始し、Main が呼び出されます。
  • Application オブジェクトが作成されます。
    • (プロジェクト テンプレート)コンストラクターは InitializeComponent を呼び出します。これにより、App.xaml が解析され、オブジェクトが作成されます。
  • Application.OnLaunched イベントが発生します。
    • (ProjectTemplate)アプリ コードによってフレームが作成され、MainPage に移動します。
    • (ProjectTemplate)Mainpage コンストラクターは InitializeComponent を呼び出します。これにより、MainPage.xaml が解析され、オブジェクトが作成されます。
    • ProjectTemplate) Window.Current.Activate() が呼び出されます。
  • XAML プラットフォームは、Measure と Arrange を含むレイアウト パスを実行します。
    • ApplyTemplate を使用すると、各コントロールに対してコントロール テンプレートのコンテンツが作成されます。これは通常、起動時のレイアウト時間の大部分です。
  • Render は、すべてのウィンドウ コンテンツのビジュアルを作成するために呼び出されます。
  • フレームはデスクトップ Windows マネージャー (DWM) に表示されます。

スタートアップの道で手間を減らす

最初のフレームに不要なものからスタートアップ コード パスを解放します。

  • 最初のフレームで不要なコントロールを含むユーザー dll がある場合は、それらを読み込むのを遅らせることを検討してください。
  • UI の一部がクラウドからのデータに依存している場合は、その UI を分割します。 まず、クラウド データに依存しない UI を表示し、クラウド依存 UI を非同期的に表示します。 また、アプリケーションがオフラインで動作するか、低速なネットワーク接続の影響を受けないように、データをローカルにキャッシュすることも検討する必要があります。
  • UI がデータを待機している場合は、進行状況 UI を表示します。
  • 構成ファイルの解析が多いアプリ設計や、コードによって動的に生成される UI には注意してください。

要素数を減らす

XAML アプリのスタートアップ パフォーマンスは、起動時に作成する要素の数と直接関連付けられます。 作成する要素が少ないほど、アプリの起動にかかる時間が短くなります。 大まかなベンチマークとして、各要素が作成に 1 ミリ秒かかると考えてください。

  • 項目コントロールで使用されるテンプレートは、複数回繰り返されるため、最も大きな影響を与える可能性があります。 ListView と GridView UI の最適化を参照してください。
  • UserControls とコントロール テンプレートが拡張されるため、それらも考慮する必要があります。
  • 画面に表示されない XAML を作成する場合は、起動時にそれらの XAML を作成するかどうかを正当化する必要があります。

Visual Studio Live Visual Tree ウィンドウには、ツリー内の各ノードの子要素数が表示されます。

ライブ ビジュアル ツリー。

遅延操作をとして使用します。 要素を折りたたんだり、不透明度を 0 に設定したりすると、要素が作成されなくなります。 x:Load または x:DeferLoadStrategy を使用すると、UI の読み込みを遅らせ、必要に応じて読み込むことができます。 これは、必要に応じて、または遅延ロジックのセットの一部として読み込むことができるように、起動時に表示されない UI の処理を遅らせるのに適した方法です。 読み込みをトリガーするには、要素の FindName のみを呼び出す必要があります。 例と詳細については、 x:Load 属性x:DeferLoadStrategy 属性を参照してください。

仮想化. UI にリストまたはリピーター コンテンツがある場合は、UI 仮想化を使用することを強くお勧めします。 リスト UI が仮想化されていない場合は、すべての要素を前もって作成するコストが発生し、起動速度が低下する可能性があります。 ListView と GridView UI の最適化を参照してください。

アプリケーションのパフォーマンスは生のパフォーマンスだけでなく、知覚に関する問題でもあります。 視覚的な側面が最初に発生するように操作の順序を変更すると、通常、ユーザーはアプリケーションの速度が速くなるような感じになります。 ユーザーは、コンテンツが画面上にあるときにアプリケーションが読み込まれたと見なします。 通常、アプリケーションは起動時にさまざまなタスクを実行する必要がありますが、そのすべてがUIを表示するために必要なわけではありません。そのため、UIよりも後に実行するか、優先度を低く設定する必要があります。

このトピックでは、アニメーション/テレビに由来する "最初のフレーム" について説明します。これは、エンド ユーザーがコンテンツを表示するまでの時間の尺度です。

スタートアップの認識を向上させる

単純なオンライン ゲームの例を使用して、スタートアップの各フェーズと、プロセス全体を通してユーザーフィードバックを提供するさまざまな手法を特定しましょう。 この例では、アクティブ化の最初のフェーズは、ユーザーがゲームのタイルをタップしてから、ゲームのコードの実行を開始するまでの時間です。 この間、システムには、正しいゲームが開始されたことを示すためにユーザーに表示するコンテンツはありません。 しかし、スプラッシュスクリーンを提供すると、そのコンテンツがシステムに与えられます。 その後、ゲームは、コードの実行を開始するときに静的スプラッシュ画面を独自の UI に置き換えることで、アクティブ化の最初のフェーズが完了したことをユーザーに通知します。

アクティブ化の 2 番目のフェーズには、ゲームに不可欠な構造体の作成と初期化が含まれます。 アプリがアクティブ化の最初のフェーズの後に使用可能なデータを使用して初期 UI をすばやく作成できる場合、2 番目のフェーズは簡単で、UI をすぐに表示できます。 それ以外の場合は、初期化中に読み込みページを表示することをお勧めします。

読み込みページの外観はユーザー次第であり、進行状況バーや進行状況リングを表示するのと同じくらい簡単です。 重要な点は、アプリが応答性を高める前にタスクを実行していることを示していることです。 ゲームの場合は、最初の画面を表示する必要がありますが、その UI では、一部のイメージとサウンドをディスクからメモリに読み込む必要があります。 これらのタスクには数秒かかります。そのため、スプラッシュ画面を読み込みページに置き換えることで、アプリはユーザーに通知を受け取り続けます。これにより、ゲームのテーマに関連する簡単なアニメーションが表示されます。

3 番目のステージは、読み込みページを置き換える対話型 UI を作成するための最小限の情報セットがゲームに追加された後に開始されます。 この時点で、オンライン ゲームで使用できる唯一の情報は、アプリがディスクから読み込んだコンテンツです。 ゲームには、対話型 UI を作成するのに十分なコンテンツを付属させることができます。オンラインゲームなので、インターネットに接続して追加情報をダウンロードするまで機能しません。 機能する必要があるすべての情報を取得するまで、ユーザーは UI を操作できますが、Web からの追加データを必要とする機能は、コンテンツがまだ読み込まれているというフィードバックを提供する必要があります。 アプリが完全に機能するまでに時間がかかる場合があるため、できるだけ早く機能を利用できるようにすることが重要です。

オンライン ゲームでのアクティブ化の 3 つの段階を特定したので、それらを実際のコードに結び付けてみましょう。

フェーズ 1

アプリを起動する前に、スプラッシュ画面として表示する内容をシステムに伝える必要があります。 これは、例のように、アプリのマニフェスト内の SplashScreen 要素にイメージと背景色を提供することによって行われます。 アプリがアクティブ化を開始すると、Windows に表示されます。

<Package ...>
  ...
  <Applications>
    <Application ...>
      <VisualElements ...>
        ...
        <SplashScreen Image="Images\splashscreen.png" BackgroundColor="#000000" />
        ...
      </VisualElements>
    </Application>
  </Applications>
</Package>

詳細については、「 スプラッシュ画面を追加する」を参照してください。

アプリのコンストラクターは、アプリにとって重要なデータ構造を初期化する場合にのみ使用します。 コンストラクターは、アプリを初めて実行するときにのみ呼び出され、必ずしもアプリがアクティブ化されるたびに呼び出されるとは限りません。 たとえば、コンストラクターは、実行され、バックグラウンドに配置され、検索コントラクトを介してアクティブ化されたアプリに対して呼び出されません。

フェーズ 2

アプリをアクティブ化するには、さまざまな理由があり、それぞれ異なる方法で処理する必要があります。 OnActivatedOnCachedFileUpdaterActivatedOnFileActivatedOnFileOpenPickerActivatedOnFileSavePickerActivatedOnLaunchedOnSearchActivated、および OnShareTargetActivated のメソッドを、それぞれのアクティベーションの理由に応じてオーバーライドすることができます。 これらのメソッドでアプリで実行する必要がある操作の 1 つは、UI を作成し、 Window.Content に割り当てて から Window.Activate を呼び出す方法です。 この時点で、スプラッシュ画面はアプリによって作成された UI に置き換えられます。 このビジュアルは、起動時に十分な情報が利用可能であれば、読み込み画面やアプリの実際のUIとして表示される可能性があります。

public partial class App : Application
{
    // A handler for regular activation.
    async protected override void OnLaunched(LaunchActivatedEventArgs args)
    {
        base.OnLaunched(args);

        // Asynchronously restore state based on generic launch.

        // Create the ExtendedSplash screen which serves as a loading page while the
        // reader downloads the section information.
        ExtendedSplash eSplash = new ExtendedSplash();

        // Set the content of the window to the extended splash screen.
        Window.Current.Content = eSplash;

        // Notify the Window that the process of activation is completed
        Window.Current.Activate();
    }

    // a different handler for activation via the search contract
    async protected override void OnSearchActivated(SearchActivatedEventArgs args)
    {
        base.OnSearchActivated(args);

        // Do an asynchronous restore based on Search activation

        // the rest of the code is the same as the OnLaunched method
    }
}

partial class ExtendedSplash : Page
{
    // This is the UIELement that's the game's home page.
    private GameHomePage homePage;

    public ExtendedSplash()
    {
        InitializeComponent();
        homePage = new GameHomePage();
    }

    // Shown for demonstration purposes only.
    // This is typically autogenerated by Visual Studio.
    private void InitializeComponent()
    {
    }
}
    Partial Public Class App
    Inherits Application

    ' A handler for regular activation.
    Protected Overrides Async Sub OnLaunched(ByVal args As LaunchActivatedEventArgs)
        MyBase.OnLaunched(args)

        ' Asynchronously restore state based on generic launch.

        ' Create the ExtendedSplash screen which serves as a loading page while the
        ' reader downloads the section information.
        Dim eSplash As New ExtendedSplash()

        ' Set the content of the window to the extended splash screen.
        Window.Current.Content = eSplash

        ' Notify the Window that the process of activation is completed
        Window.Current.Activate()
    End Sub

    ' a different handler for activation via the search contract
    Protected Overrides Async Sub OnSearchActivated(ByVal args As SearchActivatedEventArgs)
        MyBase.OnSearchActivated(args)

        ' Do an asynchronous restore based on Search activation

        ' the rest of the code is the same as the OnLaunched method
    End Sub
End Class

Partial Friend Class ExtendedSplash
    Inherits Page

    Public Sub New()
        InitializeComponent()

        ' Downloading the data necessary for
        ' initial UI on a background thread.
        Task.Run(Sub() DownloadData())
    End Sub

    Private Sub DownloadData()
        ' Download data to populate the initial UI.

        ' Create the first page.
        Dim firstPage As New MainPage()

        ' Add the data just downloaded to the first page

        ' Replace the loading page, which is currently
        ' set as the window's content, with the initial UI for the app
        Window.Current.Content = firstPage
    End Sub

    ' Shown for demonstration purposes only.
    ' This is typically autogenerated by Visual Studio.
    Private Sub InitializeComponent()
    End Sub
End Class

アクティブ化ハンドラーに読み込みページを表示するアプリは、バックグラウンドで UI を作成する作業を開始します。 その要素が作成されると、 その FrameworkElement.Loaded イベントが発生します。 イベント ハンドラーでは、現在読み込み画面であるウィンドウのコンテンツを、新しく作成したホーム ページに置き換えます。

初期化期間が長いアプリでは、読み込みページが表示されるのが重要です。 アクティブ化プロセスに関するユーザーフィードバックを提供する以外に、 Window.Activate がアクティブ化プロセスの開始から 15 秒以内に呼び出されない場合、プロセスは終了します。

partial class GameHomePage : Page
{
    public GameHomePage()
    {
        InitializeComponent();

        // add a handler to be called when the home page has been loaded
        this.Loaded += ReaderHomePageLoaded;

        // load the minimal amount of image and sound data from disk necessary to create the home page.
    }

    void ReaderHomePageLoaded(object sender, RoutedEventArgs e)
    {
        // set the content of the window to the home page now that it's ready to be displayed.
        Window.Current.Content = this;
    }

    // Shown for demonstration purposes only.
    // This is typically autogenerated by Visual Studio.
    private void InitializeComponent()
    {
    }
}
    Partial Friend Class GameHomePage
    Inherits Page

    Public Sub New()
        InitializeComponent()

        ' add a handler to be called when the home page has been loaded
        AddHandler Me.Loaded, AddressOf ReaderHomePageLoaded

        ' load the minimal amount of image and sound data from disk necessary to create the home page.
    End Sub

    Private Sub ReaderHomePageLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
        ' set the content of the window to the home page now that it's ready to be displayed.
        Window.Current.Content = Me
    End Sub

    ' Shown for demonstration purposes only.
    ' This is typically autogenerated by Visual Studio.
    Private Sub InitializeComponent()
    End Sub
End Class

拡張スプラッシュ画面の使用例については、 スプラッシュ画面のサンプルを参照してください。

フェーズ 3

アプリに UI が表示されたからといって、完全に使用できる状態であるとは限りません。 ゲームの場合、UI には、インターネットからのデータを必要とする機能のプレースホルダーが表示されます。 この時点で、ゲームはアプリを完全に機能させるために必要な追加データをダウンロードし、データの取得時に機能を段階的に有効にします。

アクティブ化に必要なコンテンツの多くをアプリと共にパッケージ化できる場合があります。 これは単純なゲームの場合です。 これにより、アクティブ化プロセスが非常に簡単になります。 ただし、多くのプログラム (ニュース リーダーやフォト ビューアーなど) は、Web から情報を取得して機能させる必要があります。 このデータは大きく、ダウンロードにかなりの時間がかかる場合があります。 アクティブ化プロセス中にアプリがこのデータを取得する方法は、アプリのパフォーマンスに大きな影響を与える可能性があります。

アプリがアクティブ化のフェーズ 1 または 2 の機能に必要なデータ セット全体をダウンロードしようとした場合は、読み込みページまたはさらに悪いスプラッシュ画面を数分表示する可能性があります。 これにより、アプリがハングしているように見えたり、システムによって終了されたりします。 アプリでは、最小限のデータをダウンロードして、フェーズ 2 のプレースホルダー要素を含む対話型 UI を表示してから、フェーズ 3 でプレースホルダー要素を置き換えるデータを段階的に読み込むようお勧めします。 データの処理の詳細については、「 ListView と GridView の最適化」を参照してください。

アプリが起動の各フェーズにどの程度反応するかは完全にユーザー次第ですが、できるだけ多くのフィードバック (スプラッシュ画面、読み込み画面、データ読み込み中の UI) をユーザーに提供すると、ユーザーはアプリとシステム全体が高速であるかのように感じます。

スタートアップ パス内のマネージド アセンブリを最小化する

再利用可能なコードは、多くの場合、プロジェクトに含まれるモジュール (DLL) の形式で提供されます。 これらのモジュールを読み込むにはディスクにアクセスする必要があり、ご想像のとおり、そのコストが増える可能性があります。 これはコールド スタートアップに最も大きな影響を与えますが、ウォーム スタートアップにも影響を与える可能性があります。 C# と Visual Basic の場合、CLR は必要に応じてアセンブリを読み込むことで、そのコストをできるだけ遅らせようとします。 つまり、CLR は、実行されたメソッドがモジュールを参照するまでモジュールを読み込むことはありません。 そのため、CLR が不要なモジュールを読み込まないよう、スタートアップ コードでアプリの起動に必要なアセンブリのみを参照します。 不要な参照を持つ未使用のコード パスがスタートアップ パスにある場合は、不要な読み込みを回避するために、これらのコード パスを他のメソッドに移動できます。

モジュールの負荷を減らすもう 1 つの方法は、アプリ モジュールを組み合わせることです。 通常、1 つの大きなアセンブリの読み込みには、2 つの小さなアセンブリを読み込むよりも時間がかかります。 これは常に可能であるとは限りません。また、開発者の生産性やコードの再利用性に大きな違いがない場合にのみ、モジュールを組み合わせる必要があります。 PerfViewWindows Performance Analyzer (WPA) などのツールを使用して、起動時に読み込まれるモジュールを確認できます。

スマート Web 要求を行う

XAML、画像、アプリにとって重要なその他のファイルなど、アプリのコンテンツをローカルにパッケージ化することで、アプリの読み込み時間を大幅に短縮できます。 ディスク操作は、ネットワーク操作よりも高速です。 初期化時にアプリで特定のファイルが必要な場合は、リモート サーバーから取得するのではなく、ディスクから読み込むことで、全体的な起動時間を短縮できます。

ジャーナルページとキャッシュページを効率的に管理する方法

Frame コントロールはナビゲーション機能を提供します。 Page (Navigate メソッド)、ナビゲーション ジャーナリング (BackStack/ForwardStack プロパティ、GoForward/GoBack メソッド)、ページ キャッシュ (Page.NavigationCacheMode)、シリアル化のサポート (GetNavigationState メソッド) を提供します。

Frame で注意する必要があるパフォーマンスは、主にジャーナリングとページ キャッシュに関連しています。

フレーム ジャーナリング。 Frame.Navigate() を使用してページに移動すると、現在のページの PageStackEntry が Frame.BackStack コレクションに追加されます。 PageStackEntry は比較的小さいですが、BackStack コレクションのサイズに組み込みの制限はありません。 ユーザーがループ内を移動し、このコレクションを無期限に拡張できる可能性があります。

PageStackEntry には、Frame.Navigate() メソッドに渡されたパラメーターも含まれています。 Frame.GetNavigationState() メソッドを機能させるには、パラメーターをプリミティブシリアル化可能な型 (int や文字列など) にすることをお勧めします。 ただし、そのパラメーターは、大量のワーキング セットまたはその他のリソースを占めるオブジェクトを参照する可能性があり、BackStack 内の各エントリのコストが高くなる可能性があります。 たとえば、パラメーターとして StorageFile を使用する可能性があり、その結果、BackStack は無期限のファイルを開いたままにしています。

そのため、ナビゲーション パラメーターを小さくし、BackStack のサイズを制限することをお勧めします。 BackStack は標準ベクター (C# の IList、C++/CX の Platform::Vector) であるため、エントリを削除するだけでトリミングできます。

ページ キャッシュの。 既定では、Frame.Navigate メソッドを使用してページに移動すると、ページの新しいインスタンスがインスタンス化されます。 同様に、Frame.GoBack を使用して前のページに戻ると、前のページの新しいインスタンスが割り当てられます。

ただし、Frame には、これらのインスタンス化を回避できるオプションのページ キャッシュが用意されています。 ページをキャッシュに格納するには、Page.NavigationCacheMode プロパティを使用します。 そのモードを [必須] に設定すると、ページが強制的にキャッシュされ、[有効] に設定すると、ページをキャッシュできるようになります。 既定では、キャッシュ サイズは 10 ページですが、これは Frame.CacheSize プロパティでオーバーライドできます。 すべての必須ページがキャッシュされ、CacheSize Required ページよりも少ない場合は、有効なページもキャッシュできます。

ページキャッシュは、インスタンス化を回避することでパフォーマンスを向上させ、ナビゲーションの向上にも役立ちます。 ページ キャッシュは、オーバーキャッシュによってパフォーマンスが低下し、ワーキング セットに影響を与える可能性があります。

そのため、アプリケーションに適したページ キャッシュを使用することをお勧めします。 たとえば、フレーム内の項目の一覧を表示するアプリがあり、項目をタップすると、その項目の詳細ページにフレームが移動するとします。 リスト ページはキャッシュに設定されている可能性があります。 詳細ページがすべての項目で同じ場合は、おそらくキャッシュする必要があります。 ただし、詳細ページの異種性が高い場合は、キャッシュをオフのままにすることをお勧めします。