Windows Phone 用アプリケーションのパフォーマンスに関する考慮事項

2012/02/09

パフォーマンスは、Windows Phone デバイスのアプリケーションを作成するときに考慮が必要な重要事項の 1 つです。Windows Phone デバイスの CPU (中央処理装置) や GPU (グラフィック処理装置) の性能は、PC に比べると限りがあります。Windows Phone では、Silverlight アプリケーションのパフォーマンスを最適化するために、Silverlight によるグラフィックなどのオブジェクトの処理方法にさまざまな変更が加えられています。Silverlight は Windows Phone に合わせて最適化されていますが、Silverlight アプリケーションで CPU と GPU の能力を最大限に活用させるためにプログラマができることは多数あります。このトピックでは、Silverlight アプリケーションのパフォーマンスを向上させる方法を、多数のコード サンプルを交えて説明します。

このトピックは、次のセクションで構成されています。

Windows Phone アプリケーションのパフォーマンスを最適化するには、次のようなツールを利用できます。

ツール

説明

Windows Phone のパフォーマンス分析

コード内のパフォーマンスに関連する問題の測定、評価、特定を行うことができます。

Windows Phone エミュレーターでのフレーム レート カウンター

フレーム レート カウンターを使用して、アプリケーションのパフォーマンスを監視します。

Silverlight EnableRedrawRegions プロパティ

このプロパティを設定すると、アプリケーション開発時のパフォーマンス チューニングに役立つ診断機能が有効になります。この機能は、Silverlight プラグインのどの領域が再描画されるかを、フレームごとに表示するものです。

これらのツールの詳細情報については、「グラフィックス中心のアプリケーションのパフォーマンスの問題を特定する」を参照してください。

アプリケーションの中でイメージを使用する場合に、パフォーマンスの向上につながるポイントは多数あります。このセクションでは、イメージに固有の考慮事項について説明します。

JPG と PNG のどちらのイメージ形式を選択するか

アプリケーションのパフォーマンス向上のためにできることの中で、最も簡単といえるのが、適切なイメージ形式の選択です。Windows Phone でサポートされるイメージ形式は、JPG と PNG の 2 つです。一般に、JPG デコーダーは PNG デコーダーに比べてはるかに高速であるため、完全に不透明なイメージには JPG を使用してください。透過性のあるイメージは、PNG として保存してください。JPG では透過性がサポートされていないからです。JPG は、写真のような連続階調イメージの場合は問題ありませんが、イメージの中の色が大きく変化する部分ではリンギング (擬似輪郭) やブロックゆがみが生じることがあります。

イメージの作成

Windows Phone OS 7.1 のパフォーマンスを最適化するうえで検討の価値のある方法の 1 つは、UI スレッドをブロックしてイメージのデコードを行う代わりに、この処理をバックグラウンド スレッドに移行するというものです。このようにするには、CreateOptions 属性を BackgroundCreation に設定します。例を示します。

<Image Height="100" Width="100" Margin="12,0,9,0">
  <Image.Source>
    <BitmapImage UriSource="{Binding ImgURL}" CreateOptions="BackgroundCreation"/>
  </Image.Source>
</Image>

イメージと XAML のどちらを選択するか

Expression Design では、複雑なビジュアルを作成できます。作成したビジュアルは、XAML とイメージ ファイルのどちらの形式でもエクスポートできます。ビジュアルが静的なものである場合は、XAML ではなくイメージとして保存することを検討してください。イメージをデコードしてレンダリングするのに比べて、XAML の場合は必要な処理量が増大する可能性があります。ビジュアルを XAML として保存した場合は、その XAML を解析してビジュアル ツリー内にオブジェクトを作成し、そのオブジェクトをレンダリングするという処理が必要になります。たとえば、チェッカー ゲームのアプリケーションを作成するとします。ゲームの各チェッカーの複雑なデザインを Expression Design で作成することもできますが、チェッカーの画像が変化することはないので、アプリケーションのパフォーマンスを考えると、XAML ではなくイメージとしてエクスポートする方が適切です。

イメージ サイズの制限

Windows Phone の画面解像度が限られていることから、パフォーマンス最適化のもう 1 つの方法として考えられるのは、イメージのサイズを 2000 x 2000 ピクセルまでに制限することです。これは、Windows Phone 環境におけるイメージ サイズの上限です。イメージが大きくなればなるほど、サンプリングの解像度は低くなります。また、イメージのサイズが 2000 x 2000 ピクセルを超えると、画面に現れるのが極端に遅くなります。

2000 x 2000 ピクセルを超えるイメージが必要な場合は、このサイズを超えないように、ファイルの一部分だけを表示してください。このようにするには、イメージを T:System.Windows.Media.Imaging.WriteableBitmap に読み込んでから LoadJpeg(WriteableBitmap, Stream) 拡張メソッドを実行します。次のコードに、大きなイメージを読み込むときに推奨される方法を示します。

このサンプルをダウンロードする

<StackPanel>
    <Image Height="3000" Width="3000" Name="image1" Stretch="Fill" />
    <Button Content="Load" Height="70" Width="152" Click="btnLoad_Click" />
</StackPanel>

private void btnLoad_Click(object sender, RoutedEventArgs e)
{
    StreamResourceInfo sri = null;
    Uri uri = new Uri("LoadJpegSample;component/Test3k3k.JPG", UriKind.Relative);
    sri = Application.GetResourceStream(uri);

    WriteableBitmap wb = new WriteableBitmap((int)this.image1.Width, (int)this.image1.Height);

    wb.LoadJpeg(wb, sri.Stream);
    this.image1.Source = wb;
}

WinPhonePerf_LoadingLargeImages

メディアを処理する方法は、Silverlight と Silverlight for Windows Phone とでは異なります。Silverlight の T:System.Windows.Controls.MediaElement で使用されるデコーダーと処理ソフトウェアは、Silverlight インストーラーに含まれています。Windows Phone の MediaElement は、ネイティブのメディア処理とハードウェア デコーダーに依存しており、これらは Windows Phone オペレーティング システムの一部です。このような理由から、メディアの処理と再生の方法においては次の 2 つの点が大きく異なっており、開発者はこのことを意識している必要があります。

  • Windows Phone 上では、再生速度と解像度が制限されます。

  • インメモリ ストリームが再生用に最適化されることはありません。

再生速度と解像度が最適になるようにメディアをエンコードする

メディアをエンコードするときは、Windows Phone での最適な再生速度と解像度の要件を満たす必要があります。サポートされているメディア コードと最適な再生速度および解像度の完全なリストについては、「Windows Phone のサポートされるメディア コーデック」を参照してください。

メディアのビルド アクションを "コンテンツ" に設定する

Windows Phone でのメディアの処理は、ファイルとネットワーク ストリームを使用するように最適化されていますが、インメモリ ストリーム向けには最適化されていません。したがって、アプリケーションにメディア ファイルが含まれている場合は (サウンド効果など)、その [ビルド アクション] を [リソース] ではなく [コンテンツ] に設定してください。コンテンツとしてコンパイルされたメディア ファイルは、アプリケーション ファイル (.XAP) とは別の Loose ファイルとして保存されます。メディア ファイルがリソースとしてコンパイルされている場合は、アクセスするには一般に、そのファイルへのストリームを取得しますが、これによってパフォーマンスが低下することがあります。再生時は、コンテンツとしてコンパイルされたメディア ファイルは直接再生されます。メディア ファイルがリソースとしてコンパイルされている場合は、再生の前にコンテンツが Windows Phone 上のファイルにコピーされますが、これによってパフォーマンスが低下することがあります。Visual Studio でファイルの [ビルド アクション] を設定する方法を次の図に示します。

WinPhonePerf_BuildActionContent

インメモリ ストリームを再生する必要がある場合は、MediaStreamSource を実装してください。MediaStreamSource を実装できない場合は、ストリームを分離ストレージ内のファイルに保存してからアクセスしてください。

オブジェクトを画面上で非表示にするには、2 つの方法があります。1 つは P:System.Windows.UIElement.Visibility プロパティ、もう 1 つは P:System.Windows.UIElement.Opacity プロパティです。ここでは、それぞれの方法がパフォーマンスに与える影響を説明します。アプリケーションでの遷移を最適化するうえで参考にしてください。

Visibility プロパティ

要素の P:System.Windows.UIElement.Visibility プロパティを Collapsed に設定すると、その要素のビジュアル データは一切ビジュアル メモリ内に保持されず、その要素に関する Silverlight の処理も一切行われません。ただし、その要素を再び画面に表示するために VisibilityVisible に設定したときは、ビジュアル ツリーの内容の再描画が必要になります。要素は、完全に再描画されます。

Opacity プロパティとビットマップ キャッシング

パフォーマンスを向上させるために要素の P:System.Windows.UIElement.Opacity プロパティを操作するという方法は、ビットマップ キャッシングを使用しているときに利用できます。ビットマップ キャッシングを使用するには、P:System.Windows.UIElement.CacheMode プロパティを T:System.Windows.Media.BitmapCache に設定します。ビットマップ キャッシングが有効になっているときは、ビジュアル要素は初回のレンダリング パスを通過した後にビットマップとして保存されます。ビジュアル要素がキャッシュされた後は、その要素のレンダリング フェーズをバイパスして、代わりに保存されているビットマップを表示することができます。Opacity を操作するときは、必ずキャッシングを有効にしてください。そうでない場合は、アプリケーションのパフォーマンスが低下します。

キャッシュされた要素の Opacity が 0 に設定されているときは、その要素をビットマップとして表現したものがメモリ内に保存されます。合成スレッドによってサポートされるもの以外のプロパティが変更されない限り、この要素はメモリに残ります。Opacity を 0 以外の値に戻すと、標準のフィル レートが適用されます。

Visibility と Opacity のどちらを選択するか

パフォーマンスを向上させるには、P:System.Windows.UIElement.Opacity とビットマップ キャッシングを使用するのが一般的です。ただし、場合によっては P:System.Windows.UIElement.Visibility プロパティを使用した方がパフォーマンスが高くなります。たとえば、アプリケーションに複数のリッチ ビジュアルが含まれている場合です。2 つの方法のパフォーマンス評価は、ケースバイケースで行ってください。このようにするには、Visibility プロパティと Opacity プロパティとの切り替えができるようにコードをプログラミングします。

オブジェクト非表示のサンプル

このサンプルを使用すると、Opacity プロパティと Visibility プロパティの設定を変更して、どちらの方がアプリケーションのパフォーマンスが高くなるかを調べることができます。

このサンプルをダウンロードする

このサンプルを実行すると、アニメーションが適用された 1 つの青色の正方形と、アニメーションが適用された 1 つの赤色の正方形と、150 個の長方形が表示されます。さらに、次のボタンも表示されます。

  • Opac x%: 長方形の Opacity を、指定の値に設定します。

  • Cache: 長方形をキャッシュするかどうかを切り替えます。既定値は true です。

  • Collapse/Visible: 長方形の Visibility プロパティのオンとオフを切り替えます。既定値は Visible です。

このサンプルをテストするには、次の方法を試します。

  • 長方形の Visibility のオンとオフを切り替え、Opacity を変更します。長方形が現れる速さは、Opacity を変更したときの方が、Visibility を変更したときよりはるかに速いことに注目してください。また、Opacity の値が 0 以外のときは、アニメーションが遅くなることにも注目してください。これは、150 個の長方形がフィル レートに影響を及ぼすからです。

  • キャッシュを無効にした状態で長方形を操作します。正方形のアニメーションの動きが滑らかになります。これは、長方形がフィル レートに影響を及ぼしていないからです。また、Opacity を設定したり Visibility のオンとオフを切り替えたりしても、長方形が現れるまでの時間は変わりません。キャッシングが無効のときは、長方形を毎回再描画しなければならないからです。

WinPhonePerf_HidingObjects

Windows Phone でのユーザー入力には、操作イベント、マウス イベント、タッチ イベントなどがあります。

操作イベントを使用する

ユーザー入力を処理するには、操作イベントを使用することをお勧めします。特別な必要性がない限り、Windows Phone の Silverlight アプリケーションではマウス イベントを使用しないでください。この理由は、パフォーマンスとハードウェア互換性です。代わりに、操作イベントを使用してください。また、TapDoubleTapHold の各イベントも、UIElement から派生した要素 (基本コントロールなど) に対して使用できます。

System.Windows.Input.Touch クラスには System.Windows.Input.Touch.FrameReported イベントがあり、個々のタッチのコンタクト ポイントを取得するときに使用されます。このイベントは Windows Phone でサポートされていますが、ピンチやストレッチなどのジェスチャを処理しようとしている場合は、このイベントはお勧めできません。個々のタッチのコンタクト ポイントが必要ない場合は、操作イベントを使用してください。

操作イベントを使用する方法については、「方法: 操作イベントを処理する」を参照してください。

進行状況バーは、時間のかかる処理を実行しているときに、アプリケーションがまだ処理中であることをユーザーに示すために使用します。ただし、現在実装されている進行状況バーは、アプリケーションのパフォーマンス低下の原因となることがあります。

ProgressBar の代わりに PerformanceProgressBar を使用する

ProgressBar に伴うパフォーマンスの問題を解決するために、マイクロソフトは代替手段として、PerformanceProgressBar (サポート対象外) を作成しました。PerformanceProgressBar では、アニメーションが UI スレッドではなくコンポジター スレッドで処理されます。

アプリケーションの進捗状況バーがシステム トレイに表示されてもかまわない場合は、ProgressIndicator の使用を検討してください。

WebClient は、Web サービス要求の実行に使用される HttpWebRequest クラスのラッパー クラスです。WebClient の方が、容易に使用できます。このクラスからは、結果のデータが UI スレッド上でアプリケーションに返され、したがってアプリケーション自身が UI スレッドへのデータのマーシャリングを管理する必要がなくなるからです。ただし、アプリケーションが Web サービスのデータを UI スレッド上で処理する場合は、その処理が完了するまでは UI が応答しなくなるため、ユーザー エクスペリエンスが低下します。特に、処理対象のデータが大量である場合です。

WebClient の代わりに HttpWebRequest を使用する

HttpWebRequest を使用して、Web サービス要求を作成します。返されたデータを非同期要求スレッド上で処理した後で、BeginInvoke を使用してデータを UI スレッドにマーシャリングします。

バッテリーを長持ちさせるために、デバイスの無線通信は、事前構成されたタイムアウト時間が経過するとオペレーティング システムによってオフに設定されます。少量のデータの要求を多数作成するアプリケーションでは、これらの要求を順次ではなく並列で実行することをお勧めします。このようにすれば、デバイスの無線スタックがスリープ状態に移行することはなくなり、したがって要求ごとに無線のオンとオフを繰り返したときの遅延を回避できます。

アプリケーションが読み込まれて起動されるときのパフォーマンスを向上させるためにできることは、多数あります。ここでは、そのいくつかを具体的に説明します。

スプラッシュ スクリーンを使用する

アプリケーションの設計によっては、リソースをあらかじめ読み込んで利用できる状態にしてからユーザーによる操作を受け付けるようにすることが必要になります。ただし、ダウンロードが完了するまでアプリケーションを表示しないというわけではありません。スプラッシュ スクリーンを利用して最初のコンテンツをユーザーに提示し、その間に残りのコンテンツを読み込みます。

Windows Phone プロジェクトのテンプレートには、スプラッシュ スクリーンのイメージが 1 つ含まれています。このイメージの名前は SplashScreenImage.jpg でなければなりません。このイメージは、アプリケーションの起動が完了するまでの間、自動的に表示されます。スプラッシュ スクリーンを使用するのは、アプリケーションの最初のページのレンダリングするのに 1 秒以上かかる場合です。Windows Phone プロジェクトのテンプレートに含まれている既定のスプラッシュ スクリーン イメージに修正を加えてください。独自のイメージを作成してもかまいません。たとえば、自社のブランドや製品情報 (アプリケーションの免責事項など) を表示する場合です。ファイル名前は必ず SplashScreenImage.jpg としてください。

スプラッシュ スクリーンに重要な情報を表示する必要があるが、アプリケーションの読み込みが短時間で完了してしまう場合は、初期画面にスプラッシュ スクリーンとまったく同じものを表示します。たとえば、ページの M:System.Windows.Controls.Page.OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs) メソッドをオーバーライドして、同じスプラッシュ スクリーン イメージを表示するポップアップを作成します。このポップアップをスプラッシュ スクリーンの代わりに表示する時間の長さを指定します。

独自のスプラッシュ スクリーン イメージを追加するには、480 x 800 の JPG イメージを作成して SplashScreenImage.jpg という名前で保存します。既定のスプラッシュ スクリーン イメージを削除してから、作成したイメージをアプリケーション プロジェクトに追加し、ビルド アクションを [コンテンツ] に設定します。これで、アプリケーションが起動されたときに独自のイメージが表示されるようになります。

別の方法としては、アプリケーションの最初のページの画面キャプチャを表示するというものがあります。このようにすると、アプリケーションが瞬時に直ちに起動されたように見えます。アプリケーションの画面キャプチャをスプラッシュ スクリーンとして使用する場合は、画面キャプチャを取るときに以下の点に注意してください。

  • アプリケーションが実行されるたびに変化するデータがある場合は、そのようなデータを非表示にします。

  • エミュレーターの表示倍率が 100% に設定されていることを確認します。

  • イメージをトリミングしてエミュレーターのクロムを取り除きます。

  • イメージのサイズが 480 x 800 で、SplashScreenImage.jpg として保存されていることを確認します。

アプリケーション アセンブリのサイズを最小にする

アプリケーション起動の時間を短縮するもう 1 つの方法は、アプリケーション アセンブリのサイズを最小にすることです。Windows Phone Marketplace で公開されるアプリケーションには、検証目的で署名が付加され、その署名の検査はアプリケーションが起動するたびに行われます。このアセンブリ署名の検査に要する時間は、アプリケーション アセンブリのサイズが大きいほど長くなります。2 回目以降の読み込み時は、署名がキャッシュされているため検査による影響は小さくなるはずですが、初回の読み込み時は依然として影響を受けます。アセンブリを小さくするためのヒントを次に紹介します。

  • 可能であれば、アセンブリに入れるイメージ、メディア、XML ファイルなどのリソースのビルド アクションは、[リソース] ではなく [コンテンツ] に設定してください。

  • イメージのソース URI のパスの先頭にスラッシュを付けます。たとえば、"/folder/myImage.jpg" のようにします。

  • 透明性が必要である場合を除いて、PNG イメージではなく JPG イメージを使用します。

  • アプリケーションがローカライズされる場合は、ローカライズされたリソースをメインのアプリケーション アセンブリに入れないでください。代わりに、言語ごとのサテライト アセンブリを作成します。詳細については、「方法: Windows Phone のローカライズしたアプリケーションを構築する」を参照してください。

注注:

再利用可能なコントロールまたはコンポーネントを作成する場合は、ビルド アクションを [リソース] に設定してリソースをアプリケーションと共にパッケージ化してください。この場合は、イメージやリソースをあまり大量に使用しないでください。

アプリケーションを小さいアセンブリに分割する

起動にかかる時間を最小化するには、アプリケーションを小さいアセンブリに分割すると、各アセンブリを必要なときだけ読み込むことができます。このようにするには、新しい Windows Phone クラス ライブラリ プロジェクトをアプリケーションに追加して、ここに、オンデマンドで読み込まれるページを入れておきます。このプロジェクトに、必要な Windows Phone ページを追加して、メインのアプリケーション プロジェクトからこのクラス ライブラリ プロジェクトを参照します。ユーザーがページ間を移動できるように、ハイパーリンク ボタンまたはイベントを追加します。次に示すコードは、ExternalPage.xaml というページに移動する方法の例です。このページは、PageInExternalAssembly というアセンブリの中にあります。

このサンプルをダウンロードする

private void button1_Click(object sender, RoutedEventArgs e)
{
     // Use the name of the separate assembly when generating the Uri for the page
     NavigationService.Navigate(new Uri("/PageInExternalAssembly;component/ExternalPage.xaml", 
           UriKind.Relative));
}

コンストラクターおよび Loaded イベントのコードを最小にする

ページのすべてのコンストラクターと E:System.Windows.FrameworkElement.Loaded イベント ハンドラー内のコードが実行された後で、アプリケーションの最初のフレームが表示されます。ページとコントロール コンストラクターは、XAML を解析して、その中で宣言されているオブジェクトをインスタンス化しますが、この処理には時間がかかることがあります。このような理由から、これらのメソッドに他にも時間のかかる処理を入れることは避けてください。ファイルを読み込むなどの、負荷のかかる処理が必要な場合は、後続のイベントで実行するか、バックグラウンド スレッドで実行するようにスケジューリングしてください。たとえば、OnNavigatedTo(NavigationEventArgs) をオーバーライドして、このメソッドの中で長時間の処理を起動します。OnNavigatedTo は、ページがアクティブ ページになったときに呼び出されます。次に例を示します。

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    // Do lengthy page initialization in a new 
    // thread so the UI can continue to update.
    System.Threading.Thread startupThread = 
        new System.Threading.Thread(new System.Threading.ThreadStart(initializePage));
    startupThread.Start();
}

void initializePage()
{
    // Do lengthy page initialization here...
}

分離ストレージの使用を監視する

P:System.IO.IsolatedStorage.IsolatedStorageSettings.ApplicationSettings オブジェクトはシングルトンであり、メモリが割り当てられてストレージから逆シリアル化されるのは、このオブジェクトが初めて使用されるとき (一般的にはアプリケーションの起動時) です。アプリケーション設定の逆シリアル化に要した時間を測定するには、ApplicationSettings にアクセスするヘルパー プロパティをアプリケーション内に作成し、このヘルパー プロパティの中にタイマーを置きます。データの逆シリアル化処理が完了までにかかる時間が 100 ミリ秒を超える場合は、この処理をバックグラウンド スレッド上の呼び出しに移動することを検討してください。

分離ストレージからのデータをページに表示する場合は、そのデータを格納するための T:System.Collections.ObjectModel.ObservableCollection`1 オブジェクトを割り当てて、このオブジェクトのコレクションを直接 UI 内の要素にバインドしてください。この ObservableCollection オブジェクトに、分離ストレージからのデータを格納します。必要に応じて、データ格納処理を複数の呼び出しに分割してください。このようにするには、M:System.Windows.Threading.Dispatcher.BeginInvoke(System.Action) メソッドを使用します。

UI スレッドのブロックを避ける

UI スレッドがブロックされると、アプリケーションの起動が遅れますが、その原因にはさまざまなものがあります。位置情報サービス、プッシュ通知、ネットワーク情報、および無線のサービスおよび API は、UI スレッドをブロックする場合があります。

位置情報サービス

Windows Phone が起動した後に、GeoCoordinateWatcherPositionChanged イベントが発生するまでに数秒間かかることがあります。DesiredAccuracy の設定に応じて、PositionChanged イベントの初回の発生までの時間は 3 ~ 13 秒となります。このような時間がかかるのは、位置情報サービスが開始して衛星の場所を特定し、その他の処理を実行するためです。Windows Phone が既に動作中の場合は、この処理に要する時間は短く、PositionChanged イベント発生までの時間は一般的に 500 ミリ秒未満です。アプリケーションからの呼び出しが位置情報イベントの発生に依存している場合は、これが原因で UI スレッドがブロックされてアプリケーションの起動が遅れることがあります。位置情報サービスを使用する方法の詳細については、「Windows Phone の場所」を参照してください。

プッシュ通知

Microsoft Push Notification Service を利用すると、アプリケーションで Web サービスからの更新情報を受け取ることができます。プッシュ通知 API は非同期型ですが、これは、Push Notification Service への呼び出しの中には長時間かかるものがあるからです。Push Notification Service の呼び出しへの応答を UI スレッドが待つことがないようにしてください。たとえば、UI スレッド上で Push Notification Service へのチャネルを作成して開くことは可能ですが、UI スレッドがイベントの発生を待つことがないようにしてください。詳細については、「Windows Phone のプッシュ通知」を参照してください。

ネットワーク情報

Windows Phone の起動時に、M:System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable の最初の呼び出しが行われますが、応答が返されるまで最大 20 秒かかることがあります。これは、Windows Phone が利用できるすべてのネットワーク接続の列挙が最初に行われるからです。GetIsNetworkAvailable メソッドの呼び出しをバックグラウンドで行う方法については、後の「バックグラウンド スレッドと非同期プログラミング」を参照してください。

ラジオ

Windows Phone の起動時に、FMRadio クラスへの呼び出しが行われますが、応答が返されるまで最大 3 秒かかることがあります。ラジオが初期化された後は、この呼び出しの応答を受け取るまでの時間は 100 ミリ秒まで短縮します。ラジオのセットアップやチューニングを UI スレッドで行わないでください。代わりに、バックグラウンド スレッドを使用してください。詳細については、後の「バックグラウンド スレッドと非同期プログラミング」を参照してください。

Silverlight for Windows Phone のグラフィックス スレッディング アーキテクチャは、デバイスに合わせて最適化されています。Silverlight for Windows Phone は、UI スレッドに加えて、合成スレッドをサポートしています。Windows Phone のパフォーマンス最適化の方法を理解するには、この 2 つの Windows Phone の主要スレッドを理解すると共に、バックグラウンド スレッドの使い方を理解することが重要です。

UI スレッド

UI スレッドは、Silverlight for Windows Phone のメイン スレッドであり、その機能は Silverlight ブラウザー プラグインの UI スレッドに非常によく似ています。以下のタスクが UI スレッドによって処理されます。

  • XAML からのオブジェクトの解析と作成。

  • 各ビジュアルが初めて描画されるときの描画。

  • フレーム単位コールバックの処理と、その他のユーザー コードの実行。

UI スレッドの処理負荷を低く抑えることは、開発するアプリケーションの応答性を高める鍵となります。「UI スレッドのブロックを避ける」で、アプリケーションの起動時の UI スレッドのブロックを回避する方法を説明しています。

合成スレッド

合成スレッドによって、本来であれば UI スレッドで処理される作業の一部が実行されるので、Windows Phone の Silverlight アプリケーションのパフォーマンスが向上します。合成スレッドによってグラフィックス テクスチャが結合され、描画のために GPU に渡されます。また、Silverlight for Windows Phone 上では、ストーリーボード駆動型のアニメーションは合成スレッド上で実行され、そのアニメーションはデバイス上の GPU によって自動的にキャッシュされて処理されます。このプロセスを、自動キャッシングと呼びます。

合成スレッドによって処理されるのは、P:System.Windows.UIElement.RenderTransform プロパティと P:System.Windows.UIElement.Projection プロパティが関連付けられている単純なアニメーションです。以下のアニメーションは、一般的に合成スレッドによって処理されます。

注注:

合成スレッドを使用するには、スケール変換が元のサイズの 50% 未満である必要があります。

さらに、P:System.Windows.UIElement.Opacity プロパティと P:System.Windows.UIElement.Clip プロパティの設定が合成スレッドによって処理されます。ただし、Opacity マスクや長方形以外のクリップが使用されている場合は、これらのプロパティの処理は UI スレッドに渡されます。

アニメーションとスレッド

前述のように、ストーリーボード駆動型のアニメーションは、合成スレッドによって処理されます。これが理想的といえるのは、アニメーションが合成スレッドから GPU に渡されて処理されるからです。さらに、合成スレッドは、CPU が過負荷状態のときに UI スレッドに比べて高頻度で実行できます。ただし、ストーリーボード アニメーションではアプリケーションの要件を満たせないこともあります。この場合の選択肢としては、コードの中でアニメーションを駆動するというものがあります。このようなアニメーションは、フレーム単位で処理されます。多くの場合は、この方法で良好な結果が得られますが、アプリケーションをフレーム単位コールバックで実行することの影響を考慮してください。

フレーム単位コールバックの処理は、必ず UI スレッド上で行われます。アニメーションが更新される速さは、UI スレッドが処理できる速さまでとなります。アプリケーションの他の処理によっては、合成スレッド上で実行した場合に比べてアニメーションのスムーズさが劣ることがあります。また、アニメーションをコード内で更新するときは、ストーリーボード内で更新するときとは異なり、アニメーションの要素が自動的にキャッシュされることはありません。アニメーション要素に手動でビットマップ キャッシュを適用した場合は、変換とブレンドの処理は GPU に渡されますが、アニメーションは依然としてフレーム単位コールバックで更新され、UI スレッドによって処理されます。この場合は、アニメーションが更新される速度は UI スレッドのフレーム レートが上限となります。

バックグラウンド スレッドと非同期プログラミング

複雑なプロセスによって UI スレッドがブロックされるのを避けるには、処理を別のスレッド (バックグラウンド スレッド) にオフロードして、その処理を非同期で実行します。たとえば、Web サービスの API はいずれも、非同期で使用されるように設計されているため、UI スレッドをブロックすることはありません。バックグラウンド スレッドを使用する場合は、データをバックグラウンド スレッドから UI スレッドに戻すメカニズムを用意する必要があります。そのためには、共有変数とイベントを使用してデータをスレッド間で受け渡すか、M:System.Windows.Threading.Dispatcher.BeginInvoke(System.Action) メソッドを使用して UI スレッドに通知を送ります。別の方法としては、T:System.ComponentModel.BackgroundWorker クラスとそのイベント ベース メカニズムを使用して非同期処理を行うというものがあります。詳細については、「方法: バックグラウンド ワーカーを使用する」を参照してください。

アプリケーションのパフォーマンスを監視してパフォーマンスの問題を特定する方法は、さまざまなものがあります。その 1 つは、アプリケーションのメモリ使用状況を監視することです。また、再描画領域の色付けやキャッシュ視覚化の機能を利用すると、再描画やキャッシュがアプリケーションでどのように使用されているかを視覚的に確認することができます。また、Windows Phone エミュレーターのフレーム レート カウンターを表示することもできます。フレーム レート カウンターを利用すると、アプリケーションのパフォーマンスをさまざまな面から監視できます。以降のセクションでは、これらの機能の使い方について説明します。

メモリ使用状況を監視する

アプリケーションのメモリ使用状況を監視するには、DeviceStatus API のプロパティを呼び出します。詳細については、「Windows Phone のデバイス ステータス」を参照してください。

再描画領域表示を有効にする

アプリケーションのどの領域が再描画されているかを目で確かめるには、Windows Phone エミュレーターの再描画領域表示機能を有効にします。ページのコンストラクション内で、P:System.Windows.Interop.Settings.EnableRedrawRegions プロパティを true に設定します。このプロパティには、次のコードに示すように現在のアプリケーション設定を通じてアクセスできます。

Application.Current.Host.Settings.EnableRedrawRegions = true;

このように設定してアプリケーションを実行すると、特定の領域が完全に再描画されたときに、その領域に色が付けられます。色の付いた領域は、GPU ではなく CPU が描画の実行に使用されたことを示します。CPU を使用して描画することを "ソフトウェア描画" と呼びます。ソフトウェア描画そのものは問題ではありません。何かを画面に表示するときに、初回は必ずソフトウェアによって描画されるからです。ただし、過剰なソフトウェア描画が行われていないかどうかを調べてください。フレームごとに色を変えるフラッシュ効果をアプリケーションで使用している場合は、その要素のビットマップ キャッシュを使用することを検討してください。ビットマップ キャッシュを有効にする方法については、前の「Opacity プロパティとビットマップ キャッシュ」を参照してください。

キャッシュ視覚化を有効にする

どのグラフィックス テクスチャが合成スレッドに渡されて、さらに GPU に渡されたかを視覚的に確認するには、キャッシュ視覚化機能を有効にします。このようにするには、ページのコンストラクター内で P:System.Windows.Interop.Settings.EnableCacheVisualization プロパティを true に設定します。このプロパティには、次のコードに示すように現在のアプリケーション設定を通じてアクセスできます。

Application.Current.Host.Settings.EnableCacheVisualization = true;

キャッシュ視覚化を有効にすると、アプリケーション内の各テクスチャが半透明になり、青みがかって表示されます。アプリケーションでどのようなテクスチャが使用されていて、どの場所で重なり合っているかがわかります。青みが最も濃い部分は、複数のテクスチャが重なり合っている領域を示します。フィル レート上昇の原因となっている可能性のある、アプリケーション内の隠れたオブジェクトが見つかります。Silverlight for Windows Phone のキャッシュ可視化機能は、他のプラットフォームの Silverlight のキャッシュ可視化とはわずかに異なります。他のプラットフォームでは、色が付いている領域が表すのは、開発者によって明示的にキャッシュされたのではない、Silverlight によって作成されたテクスチャです。Windows Phone では、色の付いた領域は合成のために GPU に渡されたテクスチャを表します。このようなテクスチャの監視が重要であるのは、アプリケーションの描画が複雑になるからであり、場合によっては GPU の処理能力を超えてしまうからです。

キャッシュ可視化が有効のときは、GPU への負荷が高まり、フレーム レートが低下することがあるため、この機能を有効にしたときはフレーム レート カウンターの数値をそのまま信用しないでください。

フレーム レート カウンターを有効にする

Windows Phone エミュレーターのフレーム レート カウンターを利用すると、開発中のアプリケーションのパフォーマンスを監視することができます。次のコードに示すように、デバッガーがアタッチされているときは、特に指定しない限り App コンストラクターの中でフレーム レート カウンターが有効化されます。

// Show graphics profiling information while debugging.
if (System.Diagnostics.Debugger.IsAttached)
{
    // Display the current frame rate counters.
    Application.Current.Host.Settings.EnableFrameRateCounter = true; 
注注:

場合によっては、フレーム レート カウンターを見るために SystemTray.IsVisible プロパティを false に設定することが必要になります。

フレーム レート カウンターを次の図に示します。

ラベル付きフレーム レート カウンター

各フレーム レート カウンターについて次の表で説明します。

カウンター

説明

合成スレッドのフレーム レート

この値は、画面が更新される速度を示します。この値からは、ストーリーボードによって駆動されたアニメーションが更新される頻度もわかります。この値は、60 に近いほど理想的です。この値が 30 を下回ると、アプリケーションのパフォーマンスが低下し始めます。このカウンターのテキストは、値が 30 を下回ると赤色で表示されます。

UI スレッドのフレーム レート

この値は、UI スレッドの実行速度を示します。UI スレッドによって処理されるものには、入力やフレーム単位コールバックがあり、さらに合成スレッドによって処理されないその他の描画もこのスレッドによって処理されます。この値が大きくなればなるほど、アプリケーションの応答が速くなります。一般に、この値が 20 を超えていれば、ユーザー入力に対する応答時間は許容範囲内となります。このカウンターのテキストは、値が 15 を下回ると赤色で表示されます。

テクスチャのメモリ使用量

この値は、アプリケーションで使用されているテクスチャがビデオ メモリやシステム メモリにコピーされた回数を表します。これは、アプリケーションの全般的なメモリ カウンターではなく、サーフェイスによって使用されているメモリのみを表すものです。

サーフェイス カウンター

この値は、処理するために GPU に渡された明示的なサーフェイスの生のカウントを示します。この数値が増加する要因として最大のものは、自動的に、または開発者によってキャッシュされた要素です。

中間サーフェイス カウンター

この値は、キャッシュされたサーフェイスの結果として生成された暗黙的なサーフェイスを表します。このサーフェイスが UI 要素と UI 要素の間に作成されるのは、アプリケーションの UI 内で要素の Z オーダーを正確に維持できるようにするためです。

フィル レート カウンター

この値は、フレームあたりの描画されるピクセルの数を、画面数に換算して表したものです。値 1 は 480 x 800 ピクセルを表します。推奨値は、約 2.5 です。このカウンターのテキストは、値が 3 を超えると赤色で表示されます。

フィル レートを監視する

フィル レートとは、各フレームを合成するために Silverlight から GPU に渡されるグラフィック テクスチャ内のピクセルの数を表します。フィル レートは実質的に、GPU がどれだけの処理を行っているかを表しています。このような理由から、アプリケーションのフィル レート監視が必要になります。フィル レートは GPU の能力を簡単に上回ることがあり、その結果フレーム レートが低下するからです。フレーム レートの低下が始まるのは、アプリケーションのフィル レートが 2 画面分のピクセル数 (1 画面は 800x480) を超えたころからです。一般に、フレーム レートの低下にユーザーが気付くのは、フィル レートが約 3.5 画面分のピクセル数に達したころからです。アプリケーションのフィル レートを特定するには、フレーム レート カウンターの最後の数値を見てください。また、UI スレッドでのフレーム レートが合成スレッドでのフレーム レートを超えることは決してありません。したがって、フィル レートが高くなりすぎると、アプリケーションの全体的なパフォーマンスに影響が及ぶことに注意してください。

フィル レート上昇の要因

テクスチャを必要とするグラフィック オブジェクトはいずれも、アプリケーションのフィル レート上昇の要因となります。テクスチャ内のピクセル数が多いほど、フィル レートが高くなります。一般に、フィル レート上昇の主な要因は 2 つあります。1 つは基本サーフェイス (キャッシュされていない要素を囲む四角形) で、もう 1 つはキャッシュされた要素です。たとえば、合成スレッド上で自動的にキャッシュされたテクスチャや、開発者が要素の T:System.Windows.Media.BitmapCache を設定することによってキャッシュした要素があります。合成スレッド上でキャッシュされるテクスチャに加えて、以下の要素も自動的にキャッシュされます。

フレーム レートとフィル レートの推奨値

次の表は、アプリケーションのパフォーマンスをチューニングするときの目標となる推奨値と上限許容値をまとめたものです。これらのカウンターのテストは、実際の Windows Phone デバイス上で行うことが重要です。エミュレーターのパフォーマンスは変動するからです。スレッド上でアニメーションの処理がまったく行われていないときは、カウンターの更新が停止することがあります。カウンターの値を常時監視したい場合は、ごく単純な繰り返しアニメーションを、開発とテストの間だけアプリケーションに追加します。このアニメーションは、アプリケーションをリリースする前に削除してください。

カウンター

赤色表示しきい値*

推奨値

上限許容値

合成スレッドのフレーム レート

30 フレーム/秒

45 フレーム/秒

60 フレーム/秒

UI スレッドのフレーム レート

15 フレーム/秒

30 フレーム/秒

60 フレーム/秒

画面フィル レート

>3

<= 2.5

3.0

*カウンターの値がこのしきいに達すると、表示が赤色に変わります。値が赤色の場合は、パフォーマンスの問題の可能性を示しています。

フィル レート テストのサンプル

このサンプルでは、アニメーション化された長方形を追加または削除したときにフィル レートがどのように変化するかを見ることができます。各長方形の大きさは画面の 8 分の 1 です。アニメーションが適用されているため、長方形はそれぞれ 1 つのテクスチャを表します。

このサンプルをダウンロードする

このサンプルを実行すると、次の 3 つのボタンが表示されます。

  • Add: 長方形を追加します。

  • Dlt: 長方形を削除します。

  • Hide: [Hide] ボタンと [Add] ボタンを非表示にして、[Dlt] ボタンを [Show] に変えます。

また、右上に 2 つの数値が表示されます。最初の数値は、画面の長方形 1 つのピクセル数を表し、2 つ目の数値は画面全体のピクセル数を表します (フィル レート)。

このサンプルをテストするには、次の方法を試します。

  • フィル レートが 2 を超えるまで長方形を追加し、フレーム レートが低下するようすを観察します。

  • 長方形を追加していき、フレーム レートが 45 ~ 60 の間の値になったら [Hide] ボタンをクリックします。フレーム レートが上昇し、フィル レートが低下するはずです。このようになるのは、ボタンを保持しているサーフェイスが縮小したためです。一番下の 2 つのボタンを非表示にすると、このサーフェイスの面積は画面の 10% 程度にまで縮小します。これらのボタンが表示されていたときは、約 90% でした。[Show] ボタンをクリックすると、フレーム レートが再び低下します。これは、サーフェイスが再び拡張したからです。

WinPhonePerf_FillRateTest

遠近法フィル レートのサンプル

このサンプルでは、平面投影 (遠近法変換) がアプリケーションのパフォーマンスに与える影響を観察できます。デザイナーが生成した XAML には、遠近法変換が多数含まれていることがあります。遠近法変換を利用すると、優れた視覚的効果を作ることができますが、アプリケーションのパフォーマンスに影響が及びます。このサンプルは、遠近法変換とアニメーションをキャッシュ化したときの動作を表すためのものです。アニメーションを伴わない遠近法変換は自動的にキャッシュされるため、アニメーションを追加しても、さらにパフォーマンスに影響が及ぶことはありません。ただし、遠近法変換のない長方形にアニメーションを追加した場合は、影響が現れます。

このサンプルをダウンロードする

このサンプルを実行すると、次の 4 つのボタンが表示されます。

  • Add: ランダムな長方形を追加します。

  • Dlt: 最新の四角形を削除します。

  • Persp: 長方形に遠近法変換を適用するかどうかを切り替えます。

  • Animate: 長方形をアニメーション化するかどうかを切り替えます。

このサンプルをテストするには、次の方法を試します。

  • 長方形を追加していき、中央の正方形のアニメーションがぎくしゃくするようになったら、[Persp] ボタンを押して切り替えます。アニメーションは再び滑らかに表示されるはずです。これは、長方形がキャッシュされなくなったからです。すべての長方形が同じサーフェイス上にあり、さらにページ上のボタンとテキストも同じサーフェイスにあります。遠近法が適用されると同時に、Silverlight によって自動的に T:System.Windows.Media.BitmapCache が各長方形に適用され、これによってサーフェイスが追加されますが、このサーフェイスはフィル レート上昇の要因となります。

  • 長方形を追加していき、中央の正方形のアニメーションがぎくしゃくし始めたら、[Animate] ボタンをクリックします。ぎくしゃくさがそれ以上進まないことに注目してください。遠近法変換は、アニメーションがなくても自動的にキャッシュされるので、アニメーションを適用しても追加のテクスチャが作成されることはありません。このことを、遠近法変換なしの長方形に対してアニメーションのオンとオフを切り替えたときの動作と比較してください。遠近法が適用されておらず、正方形以外にはアニメーションがない状態では、どれだけ長方形を追加しても、正方形のアニメーションの動きは変わりません。これらの長方形はキャッシュされないので、すべての長方形がテキストやボタンと同じサーフェイス上にあります。しかし、長方形にアニメーションを適用すると、自動的にビットマップ キャッシュが長方形に適用され、長方形のテクスチャ領域を増やすたびにフィル レートが上昇していきます。

WinPhonePerf_PerspectiveFillRate

フレーム単位コールバックのサンプル

このサンプルでは、フレーム単位コールバックを使用したアニメーションの効果を、ストーリーボード駆動のアニメーションと比較することができます。

このサンプルをダウンロードする

このサンプルを実行すると、小さい青色の正方形が表示されます。この正方形はストーリーボードを使用してアニメーション化されています (したがって合成スレッド上で実行されます)。また、次の 5 つのボタンが表示されます。

  • Add: 画面の 8 分の 1 の大きさの長方形を 1 個追加します。この長方形は、フレーム単位コールバックを使用してアニメーション化されています。

  • Dlt: 最新の四角形を削除します。

  • Redraw: P:System.Windows.Interop.Settings.EnableRedrawRegions デバッグ フラグのオンとオフを切り替えます。

  • Cache: 長方形に手動ビットマップ キャッシュを適用するかどうかを切り替えます。既定値は true です。

  • Hide/Show: 画面の一番下のボタンを表示するかどうかを切り替えます。

このサンプルをテストするには、次の方法を試します。

  • 長方形を追加していきます。しだいに、青色の正方形と長方形の動きが明らかにぎくしゃくするようになります。これは、手動キャッシュが適用されているからです。この手動キャッシュが理由で、正方形のアニメーション化は合成スレッド上で行われ、長方形のアニメーション化は UI スレッド上で行われます。どちらのスレッドも、フレームごとの長方形の描画速度は、フィル レートの制約を受けます。

  • [Cache] ボタンを押して、長方形の手動キャッシュをオフに切り替えます。正方形のアニメーションが非常にスムーズに動くようになりますが、長方形はさらにぎくしゃくするはずです。これは、キャッシュが適用されなくなったために UI スレッドがすべてのフレームの長方形を再描画するようになったからです。一方で、合成スレッドは長方形のテクスチャを処理しないようになったので、正方形のアニメーションが非常にスムーズになります。長方形がキャッシュされていないときは、メモリ内にテクスチャはありません。長方形の位置が更新されるたびに、すべてのピクセルが再描画されます。この高負荷の処理が、CPU と UI スレッドで行われます。一方、低負荷の合成スレッドは、正方形を 60 フレーム/秒で更新することができます。長方形の処理で CPU の余力がないにもかかわらずです。

  • 引き続き、[Redraw] ボタンと [Cache] ボタンを押して変化を観察します。長方形がキャッシュされている場合は、再描画領域の表示を有効にしていても、長方形がフラッシュしないことに注目してください。フラッシュとは、オブジェクトがフレームごとに再描画されることであり、避ける必要があります。長方形がキャッシュされていない場合は、フラッシュが発生し、フレームごとに長方形の再描画を示す色が表示されます。この場合は、正方形がフラッシュしないことに注目してください。正方形のアニメーションはストーリーボード駆動であり、自動的にキャッシュされるからです。

WinPhonePerf_PerFrameCallback

Performance Analysis ツールの使用

Windows Phone Performance Analysis ツールは、Windows Phone SDK の一部としてインストールされるプロファイリング ツールです。Performance Analysis ツールを使用して、グラフィックス中心のアプリケーションの実行およびメモリのパフォーマンスを判別、評価、および改善することができます。

詳細については、「Windows Phone のパフォーマンス分析」を参照してください。

表示: