Share via


Windows アプリケーションでのメモリ リークの防止

影響を受けるプラットフォーム

クライアント - Windows 7
サーバー - Windows Server 2008 R2

説明

メモリ リークは、不要になったときにアプリケーションがメモリを解放できないバグのクラスです。 時間の経過と共に、メモリ リークは、特定のアプリケーションとオペレーティング システムの両方のパフォーマンスに影響します。 大きなリークが発生すると、過剰なページングが原因で許容できない応答時間が発生する可能性があります。 最終的には、アプリケーションとオペレーティング システムの他の部分でエラーが発生します。

Windows では、プロセスの終了時にアプリケーションによって割り当てられたすべてのメモリが解放されるため、実行時間の短いアプリケーションはシステム全体のパフォーマンスに大きな影響を与えるわけではありません。 ただし、サービスやエクスプローラー プラグインなどの実行時間の長いプロセスでのリークは、システムの信頼性に大きな影響を与える可能性があり、システムを再び使用できるようにするためにユーザーに Windows の再起動を強制する可能性があります。

アプリケーションは、複数の方法で、代わりにメモリを割り当てることができます。 使用後に解放されていない場合、割り当ての種類ごとにリークが発生する可能性があります。 一般的な割り当てパターンの例を次に示します。

  • HeapAlloc 関数またはその C/C++ ランタイムと同等の malloc または new を使用したヒープ メモリ
  • VirtualAlloc 関数を使用したオペレーティング システムからの直接割り当て。
  • CreateFileCreateEventCreateThread などの Kernel32 API を介して作成されたカーネル ハンドルは、アプリケーションの代わりにカーネル メモリを保持します
  • User32 API と Gdi32 API を介して作成された GDI および USER ハンドル (既定では、各プロセスには 10,000 ハンドルのクォータがあります)

ベスト プラクティス

時間の経過に伴うアプリケーションのリソース消費量の監視は、メモリ リークを検出して診断するための最初の手順です。 Windows タスク マネージャーを使用し、"コミット サイズ"、"ハンドル"、"ユーザー オブジェクト"、"GDI オブジェクト" の各列を追加します。 これにより、アプリケーションのベースラインを確立し、時間の経過に伴うリソースの使用状況を監視できます。

Windows タスク マネージャーの [プロセス] ページを示すスクリーンショット。

次の Microsoft ツールは、より詳細な情報を提供し、アプリケーションのさまざまな割り当ての種類のリークの検出と診断に役立ちます。

  • パフォーマンス モニターとリソース モニターは Windows 7 の一部であり、時間の経過に伴うリソースの使用を監視およびグラフ化できます
  • 最新バージョンのアプリケーション検証ツールは、Windows 7 のヒープ リークを診断できます
  • WINDOWS 用デバッグ ツールの一部である UMDH は、特定のプロセスのヒープ メモリ割り当てを分析し、リークやその他の異常な使用パターンを見つけるのに役立ちます
  • Xperf は、ヒープ割り当てトレースをサポートする高度なパフォーマンス分析ツールです
  • CRT デバッグ ヒープはヒープ割り当てを追跡し、独自のヒープ デバッグ機能を構築するのに役立ちます

特定のコーディングと設計のプラクティスでは、コード内のリークの数を制限できます。

  • C++ コードでは、ヒープ割り当てと、カーネル HANDLEなどの Win32 リソースの両方にスマート ポインターを使用します。 C++ 標準ライブラリには、ヒープ割り当ての auto_ptr クラスが用意されています。 他の割り当て型の場合は、独自のクラスを記述する必要があります。 ATL ライブラリには、ヒープ オブジェクトとカーネル ハンドルの両方に対する自動リソース管理用の豊富なクラス セットが用意されています
  • _com_ptr_tなどのコンパイラの組み込み機能を使用して、COM インターフェイス ポインターを "スマート ポインター" にカプセル化し、参照カウントを支援します。 他の COM データ型にも同様のクラスがあります: _bstr_t_variant_t
  • .NET コードの通常とは異なるメモリ使用量を監視します。 マネージド コードはメモリ リークの影響を受けられません。 GC リークを見つける方法については 、「マネージド メモリ リークの追跡」 を参照してください
  • Web クライアント側コードのリーク パターンに注意してください。 COM オブジェクトと JScript などのスクリプト エンジン間の循環参照は、Web アプリケーションで大きなリークを引き起こす可能性があります。 「インターネットエクスプローラーリークパターンの理解と解決」には、このようなリークに関する詳細情報があります。 JavaScript Memory Leak Detector を使用して、コード内のメモリ リークをデバッグできます。 Windows 7 に付属している Windows インターネット エクスプローラー 8 は、これらの問題のほとんどを軽減しますが、古いブラウザーは引き続きこれらのバグに対して脆弱です
  • 関数から複数の出口パスを使用しないでください。 関数スコープで変数に割り当てられた割り当ては、関数の最後にある特定のブロックで解放する必要があります
  • 関数内のすべてのローカル変数を解放せずに、コードで例外を使用しないでください。 ネイティブ例外を使用する場合は、__finally ブロック内のすべての割り当てを解放します。 C++ 例外を使用する場合は、すべてのヒープとハンドルの割り当てをスマート ポインターでラップする必要があります
  • PropVariantClear 関数を呼び出さずに PROPVARIANT オブジェクトを破棄または再初期化しないでください

一般的な割り当てパターン:

Microsoft Tools:

その他のリンク: