次の方法で共有


この記事は機械翻訳されたものです。

JavaScript

Windows ストア アプリでメモリを管理する (機械翻訳)

David Tepper

 

Windows 8 は、流体を感じるように設計されています、生きて、させるユーザーは、急速に様々 なタスクと活動を達成するために、複数のアプリケーション間で切り替えます。 ユーザーはすぐに別の経験のうちをポップすること、彼らは決して彼らは彼らはそれを使用する必要があるときのためのアプリケーションを待つ必要があるような気がします。 このモデルでは、アプリはほとんどがユーザーによって終了いる; 代わりに彼らは頻繁に実行状態とサスペンションの間をトグルしています。 アプリを使用する前景色をもたらしたし、ユーザが別のアプリケーションに切り替えたときに背景を移動 —、すべての中にユーザーが自分のマシンをない遅くしたりより多くのアプリを開くとしても、だるく期待します。

Microsoft Windows アプリケーション エクスペリエンス チームの調査では、我々 は、いくつか Windows ストアのアプリが長時間使用中のリソースの問題が発生を開始する見てきました。 メモリ管理のバグのアプリでは、不要なメモリ使用量をリードし、マシン全体に悪影響を時間をかけて、化合物ができます。 私たちの努力の製品でこれらのバグをつぶすには、繰り返しの問題のパターンだけでなく、一般的な修正とそれらをエスケープするテクニックの数を特定しました。 この記事では、潜在的なメモリ リークを識別する方法と同様、Windows ストア アプリケーションでのメモリ管理について考える方法を説明します。 私もいくつか、チームを観察している共通の問題に成文化されたソリューションを提供します。

メモリ リークとは何ですか?

すべてのシナリオにつながるためどちらも再利用も使用できるリソースをアプリケーションは、メモリ リークと見なされます。 つまり、アプリケーションは、システムの残りの部分は、アプリケーションが終了するまでを使用できるメモリのチャンクを保持している、アプリ自体がそれを使用していない場合は、問題です。 これは典型的な説明はメモリのリーク、「コードでは、到達不能なメモリが動的に割り当て」がユーザーとシステムの両方に悪影響することができます、他の同様のリソース使用率の問題が含まれるためにもより便利ですより広範な定義です。 たとえば、アプリケーションには、コードのすべての部分から到達可能なデータを保存だけと決してその後のリリースのデータが使用されますが、この定義によると、リークにです。

時々 データは単にその特定のインスタンスのユーザーのアクションにより使用されるメモリに保存されることに注意してくださいすることが重要です。 この情報は、潜在的に、アプリケーションの有効期間中に使用可能ですかそれは、もはや必要なときに解放されますので、決して使用されているにもかかわらず、リークは考慮ができない.

影響は何ですか?

マシンが空のリソースの可用性のためにレースであったとき日は行きます。 Pc より小さいよりポータブルに前任者よりも少ない使用可能なリソースで得ています。 これは基本的に複数の経験の間で急速に、てきぱきと UI とすぐに利用できるすべてのコンテンツの期待との切り替えを含むますます共通の使用パターンと対立するものです。 今日では、アプリ時間の長い期間は、非常に多く、生きています。 同時に、マシンはそれらをすべてサポートするより少ないメモリがあるし、パフォーマンスのユーザーの期待は決して高くなっています。

しかし、数 mb のリークは本当に大きな違いを生じるか。 さて、問題はしたら、数メガ バイトをリークすることではないアプリの使用を続けている時間をかけてしばしば複合コードでのメモリ リークします。 シナリオは回復不能なリソースにつながる場合は、そのシナリオを繰り返すユーザーが引き続き回復不能なリソースの量、通常際限なく、成長します。 これは急速に少ないメモリが他のプロセスの利用可能なありユーザー属性貧しいシステム パフォーマンスに、アプリにつながるよう、全体としてのシステムのユーザビリティを低下します。 メモリ リークは表示されるとき最も深刻であります。

  • (次のフレームがビデオのデコード) など、頻繁に行う作業
  • 開始するのにはユーザーとの対話を必要としないタスク (たとえば、自動-ドキュメントを定期的に保存する)
  • (バック グラウンド タスク) などの長時間実行シナリオ

リーク (と一般的に) これらの状況は劇的にあなたのアプリケーションのメモリ使用量を増やすことができます。 このリードをことができますだけでなくシステム全体のリソースの使用率の危機に、それはまたあなたのアプリの多くの代わりに終了する可能性に使用しないときは中断なります。 アプリかかるとユーザー シナリオを経験できる容易さを減らすこと、中断のアプリよりも再アクティブ化を終了しました。 Windows プロセスの有効期間マネージャーを使用して使用していないアプリケーションからメモリを解放する方法の詳細については、建物の Windows 8 ブログで記事を参照してください bit.ly/JAqexg

だから、メモリ リークが悪いです-が、どのようにそれらを見つけるか? 私はどこで、どのように行くよ上の次の数セクションでこれらの問題を見て、見て、なぜ彼らが発生してあなたがそれらについて行うことができます。

さまざまな種類のメモリ

すべてのビットに均等に割り当てられます。 Windows 別の得票、またはビューのパフォーマンス分析作業を簡単にアプリケーションのメモリ使用の追跡。 メモリ リークを検出する方法をよりよく理解するには、これらの異なるメモリの分類について知っておくと便利です。 (このセクションを介してページング OS メモリ管理の一部の知識を想定)。

プライベート ワーキング セットページのセットをあなたのアプリケーション固有のデータを格納に現在使用してです。 「私のアプリのメモリ使用量」を考えるとき、これはおそらくあなたが考えているです。

ワーキング セットの共有ページのセットあなたのアプリを利用したが、ないあなたのプロセスによって所有されてです。 あなたのアプリケーションは、共有ランタイムまたはフレームワーク、共通の Dll またはマルチ プロセスの他のリソースを使用している場合は、それらのリソースがいくつかメモリの量をかかります。 共有のワーキング セットは、共有リソースのメジャーです。

合計作業セット (TWS) 「作業セット」と呼ばれる単に時々、プライベート ワーキング セットと共有のワーキング セットの合計です。

この番号説明測定技術を使用しますので、トーキョーワンダー サイト システムで、あなたのアプリケーションの完全な影響を表します。 ただし、潜在的な問題を追跡する場合は、あなたそれの民間調査を役に立つまたは共有これそれが漏れているあなたのアプリやアプリを使用しているリソースであるかどうかを言うことができるセットを別々 に作業あります。

メモリ リークの検出

各カテゴリにあなたのアプリケーションが使用しているメモリの量を発見する最も簡単な方法は、組み込みの Windows タスク マネージャーを使用します。

  1. Ctrl + シフト + Esc キーを押してタスク マネージャーを起動しより多くの細部は底の近くをクリックします。
  2. オプションのメニュー項目をクリックし、「常に手前」がチェックされているどうかを確認します。 これは、背景に移動して、タスク マネージャーでを探している間中断するからあなたのアプリを防ぎます。
  3. あなたのアプリケーションを起動します。 タスク マネージャーでのアプリが表示されたら、右クリックして「詳細への移動」をクリックします
  4. 上部には、上の任意の列を右クリックし、「列の選択」に行く
  5. あなたよ気づくオプションここ当分の間が、共有およびプライベート ワーキング セット (とりわけ)、「ワーキング セット (メモリ)」がチェックされているどうかを確認、ok をクリックします (を参照してください図 1).
  6. あなたが表示されます値トーキョーワンダー サイトあなたのアプリケーションのためです。

Checking the Total Working Set in Windows Task Manager
図 1 Windows タスク マネージャーでのワーキング セットの合計をチェックします。

迅速に潜在的なメモリ リークを検出するには、あなたのアプリを離れると、タスク マネージャーを開き、トーキョーワンダー サイトあなたのアプリケーションのダウンを書きます。 今あなたのアプリケーションでテストするシナリオを選択します。 シナリオでは、通常の (ページ間のナビゲーション、検索などを実行) は 4 つのステップを含む典型的なユーザーが頻繁に実行するアクションので構成されます。 ユーザーが、TWS の任意の増加に注意してください、シナリオを実行します。 その後、app を閉めないでシナリオを通じて、再度先頭から行きます。 これを 10 回行う、各手順の後、トーキョーワンダー サイトを記録します。 最初の数回のイテレーションを増やすし、高原に TWS が普通です。

あなたのアプリケーションのメモリ使用量は、今まで元のレベルにリセットせず、シナリオが実行された各時刻化したか。 可能な場合は、このシナリオでは、メモリ リークがあるし、次の提案を見てする必要があります。 素晴らしい場合、! しかし、他のシナリオであなたのアプリケーションは、特にそれらは非常に一般的で、または画像などの大規模なリソースを使用して確認してください。 仮想マシンまたはリモート デスクトップを介してこの処理を実行ただしを避ける; これらの環境はリークを探しているときに偽陽性をリードし、メモリ使用率を超えて実際の値を増加できます。

Pre-Windows 8 メモリー リーク検出ツールを使用してください。

Windows ストア アプリケーションで問題を識別する既存のメモリ リークの検出ツールを使用できるか不思議に思うかもしれません。 Windows 8 で動作するこれらのツールが更新されていない限り、彼らは「(これは懸濁液によって置き換えられています)、通常のシャット ダウンのアプリの欠如によって混同されるよ」は非常に本当らしい。 この問題を回避するには、直接外部終端を介して強制的に閉じるのではなく、整然としたファッションでアプリケーションを閉じるに AppObject「出口」機能を使用することができます。

  • C++—CoreApplication::Exit();
  • C#—Application.Current.Exit();
  • JavaScript—window.close();

この手法を使用すると、あなたの製品の場所でこのコードを出荷しないことを確認します。 あなたのアプリ停止してもトリガーを再アクティブ化する必要が任意のコードを呼び出すことはありません (再開) の代わりにそれが開かれるたび。 このテクニックをデバッグ目的でのみ使用される、Windows ストアにアプリを提出する前に削除する必要があります。

メモリ リークの共通のソース

このセクションでは我々 は開発者にすべての種類のアプリとの言語の間で実行を見てきたいくつかの一般的な落とし穴について説明しますあなたのアプリケーションでこれらの問題に対処する方法だけでなく。

イベント ハンドラー イベント ハンドラーは、メモリ リークの Windows ストアのアプリで見てきたは、最も一般的なソースです。 根本的な問題は、イベント ハンドラーの仕組みについての理解の欠如です。 イベント ハンドラーが実行されるだけのコードではありません。 彼らは、データ オブジェクトを割り当てられます。 彼らは他のものへの参照を保持し、彼らがへの参照を保持する明白でないかもしれません。 概念的には、インスタンス化と、イベント ハンドラーの登録には、3 つの部分で構成されています。

  1. イベントのソース。
  2. イベント ハンドラー メソッド (実装)
  3. メソッドをホストするオブジェクト

たとえばに示す、LeakyApp と呼ばれるアプリ見てみましょう図 2

図 2 LeakyApp

public sealed partial class ItemDetailPage : 
  LeakyApp.Common.LayoutAwarePage
{
  public ItemDetailPage()
  {
    this.InitializeComponent();
  }
  Protected override void OnNavigatedTo(NavigationEventArgs e)
  {
    Window.Current.SizeChanged += WindowSizeChanged;
  }
  private void WindowSizeChanged(object sender,
    Windows.UI.Core.WindowSizeChangedEventArgs e)
  {
    // Respond to size change
  }
  // Other code
}

LeakyApp コードは、イベント ハンドラーの 3 つの部分を示しています。

  • Window.Current (火) に由来するオブジェクトであるイベント。
    • ItemDetailPage のインスタンスを受け取るオブジェクトです (シンク) イベント。
  • WindowSizeChanged は、ItemDetailPage インスタンスのイベント ハンドラー メソッドです。

イベント通知を登録すると、現在のウィンドウ オブジェクト イベント ハンドラーで、ItemDetailPage オブジェクトへの参照を示すようにいる図 3。 この参照は ItemDetailPage オブジェクトの現在のウィンドウ オブジェクトが生きている限り、または現在のウィンドウ オブジェクト項目への参照を削除するまで生きているままにします­DetailPage インスタンス (今のところ、これらのオブジェクトへの他の外部参照を無視)。

A Reference to the Event Handler
イベント ハンドラーへの参照を図 3

生きている間、ItemDetailPage のインスタンスに対して正常に動作する Windows のランタイム (WinRT) 推移的インスタンスを使用しているすべてのリソース生き続ける、注意してください。 インスタンスへの参照を配列や画像などの大規模な割り当てを含める必要があります、これらの割り当てのインスタンスの有効期間を生きて滞在します。 事実上、イベント ハンドラーの登録、イベント ハンドラーとその依存関係のすべてのイベント ソースの有効期間と一致するを含むオブジェクトのインスタンスの有効期間を拡張します。 もちろん、これまでのところ、このリソースのリークではありません。 それは単に、イベントのサブスクライブの結果です。

ItemDetailPage は、アプリケーションのすべてのページに似ています。 ユーザーがページに移動、彼らは別のページに移動するときは、もはや必要なときに使用します。 戻って ItemDetailPage にユーザーを移動して、アプリケーションは、通常、ページの新しいインスタンスを作成します SizeChanged イベントを受信するには、現在のウィンドウの新しいインスタンスを登録します。 この例では、バグは、しかし、ItemDetailPage からユーザーを移動すると、ページ ウィンドウの現在の SizeChanged イベントからイベント ハンドラーの登録を解除する失敗です。 ItemDetailPage からユーザーを移動し、現在のウィンドウは、まだ前のページへの参照がページ SizeChanged イベントを発生する現在のウィンドウを続けています。 戻って ItemDetailPage にユーザーを移動すると、この新しいインスタンスも、現在のウィンドウに示すように登録図 4

A Second Instance Registered with the Current Window
図 4 2 番目のインスタンスを現在のウィンドウを登録

5 ナビゲーション後、5 つの ItemDetailPage オブジェクトは、現在のウィンドウに登録されている (を参照してください図 5) と彼らのすべての依存リソースの生きています。

Five Objects Registered with the Current Window
図 5 5 つのオブジェクトを現在のウィンドウを登録

これらの使用のない ItemDetailPage インスタンスは決して使用または再利用できるリソースです。 彼らは効果的に流出されます。 この記事から一つを取る場合は、それ彼らは、もはや必要なときにイベント ハンドラーを登録解除の最も一般的なメモリ リークを防ぐために最善の方法だかどうかを確認します。

LeakyApp の問題を解決するには、現在のウィンドウからは、SizeChanged イベントのハンドラーへの参照を削除する必要が。 あります これは、ビューから、ページを移動した場合、イベント ハンドラーからサブスクライブを解除によって行うことができますましょう。

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
  Window.Current.SizeChanged -= WindowSizeChanged;
}

このオーバーライドを ItemDetailPage クラスに追加した後は、もはや ItemDetailPage インスタンスを蓄積し、リークを修正します。

メモ任意のオブジェクトをこの種類の問題が発生することが — 任意の寿命の長いオブジェクトすべてが参照は生き続けます。 彼らはこの問題の最も一般的なソースであるために、イベント ハンドラーのうちここを呼び出す — しかし、説明するように、彼らは、もはや必要に応じてオブジェクトのクリーンアップ大規模なメモリ リークを回避する最善の方法です。

循環参照内のイベント ハンドラーがクロス GC 境界特定イベントのハンドラーを作成するときは、イベントがトリガーされるときに呼び出される関数を指定して開始し、その問題のイベントを受け取ることをオブジェクトにハンドラーをアタッチします。 実際に、イベントが発生すると、処理関数は当初「イベント ソース」として知られている、イベントを受け取ったオブジェクトを表すパラメーターをが次のイベント ハンドラーはクリックして、"sender"パラメーターをイベント ソースです:

private void Button_Click(object sender, RoutedEventArgs e)
{
}

定義では、イベント ソースのイベント ハンドラーへの参照がまたは他のソースがイベントを起動できませんでした。 イベント ハンドラー内のソースへの参照をキャプチャして、ハンドラーは、現在のソースの参照が循環参照を作成しました。 これはかなり一般的なパターンの動作を見てみましょう:

// gl is declared at a scope where it will be accessible to multiple methods
Geolocator gl = new Geolocator();
public void CreateLeak()
{           
  // Handle the PositionChanged event with an inline function
  gl.PositionChanged += (sender, args) =>
    {
      // Referencing gl here creates a circular reference
      gl.DesiredAccuracy = PositionAccuracy.Default;
    };
}

これはたとえば、gl と送信者は同じです。 ソースをハンドラーと逆参照ですので gl ラムダ関数を参照して循環参照を作成します。 通常 CLR と JavaScript のガベージ コレクター (Gc) がこのようなケースを処理するのに十分なインテリジェントなのでこのような循環参照の問題ではないです。 循環参照の片側 GC 環境に属していない、または別の GC 環境に属している場合は、ただし、問題が出現することができます。

Geolocator は、WinRT オブジェクトです。 WinRT オブジェクトは C または C++ で実装されている、したがって、GC ではなく参照カウント システムを使用します。 CLR GC はこの循環参照をクリーンアップしようとするときは、独自に gl にクリーンアップできません。 同様に、物事の C/C++ 側はどちらかをクリーンアップ得る won't ので、gl の参照カウントはゼロに到達します。

もちろん、これは問題を示すために非常に単純な例です。 それは単一ではなかったどのような場合、代わりに UI 要素 (または JavaScript div) パネルなどの大規模なグループ オブジェクトですか? リークは、すべてのそれらのオブジェクトを包含する、ソース ダウン追跡は非常に難しいでしょう。

これらの循環の多くが検出、GC によってクリーンアップできるように様々 な緩和策の場所でです。 たとえば、JavaScript コードのサイクルでは、WinRT イベント ソースを含む循環参照 (またはイベント ソースとしての XAML のオブジェクトの循環参照) が正しく再利用されます。 しかし、循環のすべてのフォーム (JavaScript イベントなど、c# のイベント ハンドラーを)、覆われている、成長の数と複雑さ、イベント ソースへの参照のように、GC の特別な軽減策が少ない保証になります。

イベント ソースへの参照を作成する場合は、常に明示的にイベント ハンドラーまたは null 参照を後で真円度ダウンを引き裂くし、(これは、作成するオブジェクトの有効期間についての推論にさかのぼる) 任意のリークを防ぐために登録を解除することができます。 しかし、イベント ハンドラーはソースへの参照を保持している場合は、プラットフォームが提供される軽減または何リソース使用率の非常に大きな問題になることを防ぐために明示的なコードに依存する必要はありません。

境界のないデータ構造を使用してキャッシュの多くのアプリケーションでは、いくつかの経験を改善するために、ユーザーの最近の活動に関する情報を格納する意味が。 たとえば、最後の 5 が表示されます検索アプリをユーザーが入力したクエリ これを達成する 1 つのコーディング パターンは、単にリストまたは他のデータ構造での各クエリを格納および提案を与えるために時間が来るときトップ 5 を取得するには、です。 このアプローチの問題は、app 長時間開いたままの場合、リストは最終的に不必要なメモリを大量に消費を取って、際限なく成長することです。

残念ながら、GC (または他のメモリ マネージャー) 方法を決して使用される非常に大規模なまだ、到達のデータ構造についての理由がありません。 この問題を回避するには、ハード制限をキャッシュに格納する項目の数を維持します。 うちの古いデータを定期的に位相およびこれらの種類のデータ構造を解放するために終了して、アプリケーションに依存しないでください。 情報時間-敏感なまたは特に簡単に再構成する場合は、完全に停止する際、キャッシュを空にすることをお勧めします。 場合は、キャッシュ ローカルに状態を保存し、メモリ内のリソースを解放; 履歴書を再取得することができます。

大への参照を保持を避けるために中断

言語に関係なく、中断中の大規模な参照を保持 UX の問題につながることができます。 システムがアプリを終了することによってのみ取得できる追加のメモリを必要とせず、他の実行プロセスの要求をサービスすることができる限りあなたのアプリのため中断されたままになります。 中断されたことを意味あなたのアプリは、ユーザーがより簡単にアクセスできるので、メモリ フット プリントは、懸濁液中に小さく保つためにあなたの最善の利益です。

これを達成する簡単な方法は、単に無料のラージ オブジェクトへの参照が中断する履歴書に再構成することがでく場合です。 たとえば、アプリケーションにメモリ内の参照のローカル アプリケーション データを保持している場合は、参照を解放すると、大幅に、プライベート ワーキング セットを下げる可能性があります、それはこのデータがどこに行っていないので、履歴書に再取得するは簡単です。 (アプリケーション データについてを参照してください bit.ly/MDzzIr.)

変数を完全に解放するには、割り当てるを null 変数 (と変数へのすべて参照)。 C++ では、このすぐにメモリが解放されます。 これらの変数のメモリを再利用するアプリケーションが中断されると Microsoft .NET Framework と JavaScript アプリケーションでは、GC が実行されます。 これは、正しいメモリ管理を確保するには、多層防アプローチです。

アプリケーションを JavaScript で書かれている .NET GC は実行することはありませんし、いくつかの .NET コンポーネントとノート、しかしを中断します。

JavaScript の Windows ストア アプリケーションでのメモリ管理

リソース効率的な Windows の店の apps を作成するための JavaScript でいくつかのヒントはこちらです。 これらの私たちは私たち自身のアプリで見たの一般的な問題のための推奨される修正プログラムと彼らと設計念頭に頭痛を引き起こす前に多くの潜在的な問題を食い止めるために役立ちます。

コードの品質のツールを使用して 、しばしば見過ごされてリソース フリーウェア コード品質ツールをウェブ上のすべての JavaScript 開発者利用します。 これらのツールは、メモリ リークなど、一般的な問題の多くのコードを検査、早期の問題をキャッチするためあなたの最高を賭けることができます。 2 つの便利なツールです JSHint (jshint.com) と JSLint (jslint.com)。

Strict モードを使用して JavaScript コード内で変数を使用できる方法を制限する「厳格な」モードがあります。 これらの制限は、余分なルールに違反しているときにスロー取得ランタイム エラーとして自らを提示します。 このようなコーディングの制限は、グローバル スコープの変数を暗黙的に宣言など、共通のメモリ リークを避けることができます。 Strict モード、その使用、課される制限については、MSDN ライブラリの記事を「Strict モード (JavaScript)」で確認 bit.ly/RrnjeU

クロージャでの循環参照を避けるため JavaScript ラムダ (またはインライン) 関数が使用されるたびに、変数への参照を格納するのはかなり複雑なシステムがあります。 基本的に、それが呼び出されたときを正しく実行するには、インライン関数のために JavaScript はクロージャとして知られている参照のセットで利用可能な変数のコンテキストを格納します。 これらの変数は、インライン関数が参照されなくような時間までメモリに維持されます。 例を見てをみましょう:

myClass.prototype.myMethod = function (paramA, paramB) {
  var that = this;
  // Some code
  var someObject = new someClass(
    // This inline function's closure contains references to the "that" variable,
    // as well as the "paramA" and "paramB" variables
    function foo() {
      that.somethingElse();
    }
  );
  // Some code: someObject is persisted elsewhere
}

SomeObject 永続化された後は、「その」「パラマ」によって、メモリを参照、someObject が破棄されるかは someClass のコンス トラクターで渡されたインライン関数への参照を解放するまで"paramB"をクリアされません。

インライン関数への参照がリリースされていない場合は、閉鎖参照が永久にリークを引き起こして、メモリに置かれますから問題のインライン関数のクロージャで発生します。 クロージャ自体への循環参照が含まれる場合は、これが発生する最も一般的な方法です。 これは通常、インライン関数、インライン関数を参照する変数を参照する場合に発生します。

function addClickHandler(domObj, paramA, paramB, largeObject) {
  domObj.addEventListener("click",
  // This inline function's closure refers to "domObj", "paramA",
  // "paramB", and "largeObject"
    function () {
      paramA.doSomething();
      paramB.somethingElse();
    },
  false);
}

この例では domObj には (を通じてイベント リスナー) インライン関数への参照が含まれています、インライン関数のクロージャに戻ってそれへの参照が含まれています。 ラージ オブジェクトで使用されていないため、意図は、それがスコープ外になるし、埋め立てを取得です。 ただし、クロージャの参照し、domObj メモリで生き続けています。 この循環参照は、domObj イベント リスナー参照を削除するか null に設定を取得するまでのリークやガベージになります。 このような何かを達成するために適切な方法で示すように、タスクを実行する関数を返す関数を使用することです図 6

図 6 関数スコープを使用して、クロージャでの循環参照を避けるために

function getOnClick(paramA, paramB) {
  // This function's closure contains references to "paramA" and "paramB"
  return function () {
    paramA.doSomething();
    paramB.somethingElse();
  };
}
function addClickHandlerCorrectly(domObj, paramA, paramB, largeObject) {
  domObj.addEventListener(
    "click",
  // Because largeObject isn't passed to getOnClick, no closure reference
  // to it will be created and it won't be leaked
  getOnClick(paramA, paramB),
  false);
}

このソリューションでは、domObj への参照を閉鎖を排除が、として、イベント ハンドラーの実装を必要しているパラマと paramB への参照は、存在します。 ないリーク パラマまたは paramB することを確認するには、まだイベント リスナーの登録を解除またはちょうど domObj ガベージを取得するときに自動的に埋め立てを得るを待つのいずれかする必要があります。

URL.createObjectURL によって作成されたすべての Url を取り消す 、URL.createObjectURL メソッドを使用して、要素を使用できる URL を作成するメディアのオーディオ、ビデオまたは img 要素をロードする一般的な方法であります。 このメソッドを使用すると、内部リファレンスをあなたのメディアを保つためにシステムに指示します。 システムでは、この内部リファレンスを使用して stream オブジェクトに適切な要素します。 ただし、データが必要なくなったときは、それは明示的にそれを解放する言ったしているまでそれが内部リファレンス生きているメモリで保持して、システムが分かっていません。 こうした内部参照を消費することができます大量のメモリと簡単に誤って不必要にそれらを保持します。 これらの参照を解放するには、2 とおりの方法があります。

  1. URL.revokeObjectURL メソッドを呼び出すと、URL を渡して、明示的に URL を取り消すことができます。
  2. URL.createObjectURL の oneTimeOnly プロパティを true に設定を一度使用後自動的に URL を取り消すことをシステムに伝えることができます。
var url = URL.createObjectURL(blob, {oneTimeOnly: true});

一時オブジェクトに対して弱い参照を使用あなたがあなたのアプリケーションのさまざまな部分で使用する必要があるドキュメント オブジェクト モデル (DOM) ノードによって参照されるラージ オブジェクトがある想像してください。 今、任意の時点で、オブジェクトを解放できることをとします (たとえば、node.innerHTML ="")。 どのようにそれは完全に任意の時点でクリアできるように、オブジェクトへの参照を保持しないように確認しますか? ありがたいことに、Windows のランタイムは、オブジェクトの「弱い」への参照を格納することができますこの問題を解決するを提供します。 弱い参照はそれが参照するオブジェクトのクリーンアップから GC をブロックしないし、逆参照すると、オブジェクトまたは null を返すことができます。 どのようにこれが役に立つことができますをよりよく理解するには、例で見て図 7

図 7 JavaScript のメモリ リーク

function addOptionsChangedListener () {
  // A WinRT object
  var query = Windows.Storage.KnownFolders.picturesLibrary.createFileQuery();
  // 'data' is a JS object whose lifetime will be associated with the  
  // behavior of the application.
Imagine it is referenced by a DOM node, which
  // may be released at any point.
// For this example, it just goes out of scope immediately,
  // simulating the problem.
var data = {
    _query: query,
    big: new Array(1000).map(function (i) { return i; }),
    someFunction: function () {
      // Do something
    }
  };
  // An event on the WinRT object handled by a JavaScript callback,
  // which captures a reference to data.
query.addEventListener("optionschanged", function () {
    if (data)
      data.someFunction();
  });
  // Other code ...
}

イベント リスナーのクエリによって参照されているのでこの例では、データ オブジェクト再利用されていません。 アプリケーションの意図データ オブジェクトをクリアするには (さらに試みがそうようになりますので)、これはメモリ リークです。 この問題を回避するには、WeakWinRTProperty API のグループは、次の構文を使用できます。

msSetWeakWinRTProperty(WinRTObj, "objectName", objectToStore);

WinRTObj IWeakReference をサポートする WinRT オブジェクトですデータにアクセスするには、キーの objectName のです、objectToStore を格納するデータです。

情報を取得するには、次のように使用します。

var weakPropertyValue = msGetWeakWinRTProperty(WinRTObj, "objectName");

WinRTObj プロパティが格納されたおよび objectName データが格納されていたキー WinRT オブジェクトです。

戻り値が null または値 (objectToStore) がもともと格納します。

図 8 の addOptions リークを修復する方法を示しています­ChangedListener 関数。

図 8 の弱い参照を使用してメモリ リークを避けるために

function addOptionsChangedListener() {
  var query = Windows.Storage.KnownFolders.picturesLibrary.createFileQuery();
  var data = {
    big: new Array(1000).map(function (i) { return i; }),
    someFunction: function () {
      // Do something
    }
  };
  msSetWeakWinRTProperty(query, "data", data)
  query.addEventListener("optionschanged", function (ev) {
    var data = msGetWeakWinRTProperty(ev.target, "data");
    if (data) data.someFunction();
  });
}

他の参照を削除するデータ オブジェクトへの参照が弱い、ので、ガベージとそのメモリが解放されます。

JavaScript を使用して Windows ストアのアプリを構築

心でリソース使用率をアプリケーションのデザイン スポット修正およびメモリの管理に固有のコーディングの必要性あなたのアプリの開始からのリークする耐性を作るを減らすことができます。 それが起こるときリークを識別しやすいようにセーフガードで構築することもできます。 このセクションでは独立して使用することができます javascript または一緒に維持しやすいリソース効率的なアプリケーションを作成するのに書かれて Windows ストア アプリケーションを構築する 2 つの方法を説明します。

アーキテクチャの処分 Dispose アーキテクチャのリソースを解放する一貫した、簡単かつ堅牢な方法を持っていることによって彼らの始まりでメモリ リークを停止するには素晴らしい方法であります。 あなたのアプリの心にこのパターンを各クラスまたはラージ オブジェクト メモリを再利用する関数 (通常、dispose という名前) を実装することを確認することです設計の最初のステップ各オブジェクトにそれへの参照を関連付けられています。 2 番目のステップは上のオブジェクトの dispose メソッドを呼び出します (また、通常、dispose という名前) 広く到達可能な関数を実装するのパラメーターとして渡す、その後 null オブジェクト自体です。

 

var dispose = function (obj) {
  /// <summary>Safe object dispose call.</summary>
  /// <param name="obj">Object to dispose.</param>
  if (obj && obj.dispose) {
    obj.dispose();                
  }
  obj = null;
};

目標は、アプリがツリー状の構造でかかる、dispose を呼び出してリソースを解放します、内部の dispose メソッドを持つ各オブジェクトをすべてそれの参照とオブジェクト メソッドです。 その方法完全オブジェクトとその参照のすべてを解放するには、すべて行う必要がある呼び出し dispose(obj) !

あなたのアプリケーションの各シナリオの主要な遷移で dispose すべての最上位レベルのオブジェクトの呼び出しだけが必要は、もはやです。 空想取得したい場合は、1 つの主要な「シナリオ」オブジェクトの一部であるすべてのこれらのトップレベルのオブジェクトを持つことができます。 シナリオの間で切り替える場合は、単に呼び出し、トップレベルのシナリオ オブジェクトの破棄し、アプリをスイッチング シナリオのために新しいものをインスタンス化します。

アーキテクチャの膨張 「肥大化」アーキテクチャをより簡単に識別するときにそれらを解放する前にオブジェクトが本当に大規模な右ことによってメモリ リークが発生していることができます。 オブジェクトが実際にリリースされていない場合は、この方法では、アプリのトーキョーワンダー サイトへの影響は明らかで 。 もちろん、このパターンは、開発時にのみ使用する必要があります。 スパイキングニューロンのメモリ使用量を (一時的にでも) 他の終了をユーザーのマシンを強制できますアプリを停止アプリは決してこの場所で、コードを出荷してください。

オブジェクトを人為的に膨張するには、非常に大きな配列をアタッチとして単純なものを行うことができます。 Join 構文を使用してすばやくそれが著しく大きいに接続されている任意のオブジェクトを作るいくつかのデータは、配列全体を塗りつぶします。

var bloatArray = [];
bloatArray.length = 50000;
itemToBloat.leakDetector = bloatArray.join("#");

このパターンを効果的に使用するには、オブジェクト コードによって解放されることになっている場合を識別する良い方法必要があります。 あなた、リリースでは、各オブジェクトに対して手動でこれを行うことができますが、2 つのより良い方法です。 単に説明した Dispose アーキテクチャを使用している場合は、問題のオブジェクトの dispose メソッドで肥大化のコードを追加します。 Dispose が呼び出されると、そのようにあなたは、オブジェクトは、本当に又は削除の参照のすべてがあったかどうかがわかります。 DOM の要素に対する JavaScript のイベント DOMNodeRemoved を使用する 2 番目のアプローチであります。 ノードが削除される前にこのイベントが発生したため、これらのオブジェクトのサイズが肥大化し、本当に再利用しているかどうかを参照してください。

時々、GC 実際に未使用のメモリを再利用するいくつかの時間がかかることに注意してください。 非常に急速に成長している場合は、アプリのリークは、シナリオをテストする場合、リークを確認するために間を待つ; GC は、パスまだしていない可能性があります。 待機の後、TWS はまだ高い場合は、シナリオをもう一度やり直してください。 アプリのトーキョーワンダー サイトがまだ大きい場合は、リークが発生は非常に本当らしい。 あなたのソースに体系的にあなたのアプリケーション内のオブジェクトからこの肥大化のコードを削除して磨くことができます。

今後の展開

私はあなたの強力な基盤を識別、診断および Windows ストアのアプリでのメモリ リークを修復するため与えてくれた願っています。 しばしば結果のデータの割り当てと再利用をどのように発生する誤解からをリークします。 これらのニュアンスの知識 — 大きな変数への参照を明示的にヌルなどの簡単なトリックと組み合わせて — ユーザーのマシン使用の日でも遅くない効率的なアプリの確保に向けた長い道のりを移動します。 あなたの詳細については MSDN ライブラリの記事「理解と解決インターネット エクスプ ローラーのリーク パターン」関連のトピックをカバー、インターネット エクスプ ローラー チームによってを確認できますで探しているなら bit.ly/Rrta3P

David Tepper Windows アプリケーション エクスペリエンス チームのプログラム マネージャーです。 彼はアプリケーション モデルの設計とアプリケーションの展開 2008 年以来、主に Windows ストア アプリケーションのパフォーマンスを中心に取り組んでいるし、それらのアプリが深く提供するために Windows を拡張する方法の機能を統合*.***

この記事のレビュー、次技術専門家のおかげで。ジェリー Dunietz、マイク ヒルバーグ マティアス Jourdain、仮面 Moutafov、ブレント学長、Chipalo ストリート