.NETでメモリリークを見つけるのに役立つ戦略とツールは何ですか。


152

私はC ++を10年間書きました。メモリの問題が発生しましたが、かなりの労力で修正できました。

ここ数年、私はC#を書いてきました。まだ多くのメモリの問題が発生しています。非決定性のため、診断と修正は困難です。C#の哲学は、確実にそうする場合にはそのようなことを心配する必要がないということです。

私が見つけた特定の問題の1つは、コード内のすべてを明示的に破棄してクリーンアップする必要があることです。私がそうしないと、メモリプロファイラーは本当に役に立ちません。なぜなら、あなたの周りに非常に多くのチャフが浮かんでいるため、表示しようとしているすべてのデータ内にリークを見つけることができないからです。私は間違った考えを持っているのか、あるいは私が持っているツールが最高ではないのかと思います。

.NETのメモリリークに対処するには、どのような戦略とツールが役立ちますか?


投稿のタイトルが投稿の質問と実際に一致していません。タイトルを更新することをお勧めします。
ケビン

あなたが正しい。申し訳ありませんが、私が探している現在のリークに少しうんざりしていました!タイトルを更新しました。
スコットランガム、

3
@スコット:.NETにうんざりしないでください、それは問題ではありません。あなたのコードです。
GEOCHET 2008

3
ええ、私のコード、または私が使用する喜びがあるサードパーティのライブラリ。
スコットランガム、

@スコット:私の答えを見てください。MemProfilerはそれだけの価値があります。これを使用すると、.NET GCの世界をまったく新しいレベルで理解できます。
GEOCHET 2008

回答:


51

メモリリークが疑われる場合は、ScitechMemProfilerを使用します。

これまでのところ、非常に信頼性が高く、強力であることがわかりました。それは、少なくとも一度は私のベーコンを救いました。

GCは.NET IMOで非常にうまく機能しますが、他の言語やプラットフォームと同じように、悪いコードを書くと悪いことが起こります。


3
ええ、私はこれでうまくいきました、そしてそれは私がいくつかのトリッキーなリークの底に到達するのを助けました。私が判明した最大のリークは、相互運用機能を介してアクセスしたアンマネージコードのサードパーティライブラリが原因であることが判明しました。このツールがアンマネージコードとマネージコードのリークを検出したことに感銘を受けました。
スコットランガム

1
これは結局私にとってうまくいったので、これを答えとして受け入れましたが、他のすべての答えは非常に便利だと思います。ちなみに、このツールはより一般的にはSciTechのMemプロファイラーと呼ばれています!
スコットランガム

41

忘れるだけの問題の場合は、このブログ投稿で説明されている解決策を試してください。ここに本質があります:

    public void Dispose ()
    {
        // Dispose logic here ...

        // It's a bad error if someone forgets to call Dispose,
        // so in Debug builds, we put a finalizer in to detect
        // the error. If Dispose is called, we suppress the
        // finalizer.
#if DEBUG
        GC.SuppressFinalize(this);
#endif
    }

#if DEBUG
    ~TimedLock()
    {
        // If this finalizer runs, someone somewhere failed to
        // call Dispose, which means we've failed to leave
        // a monitor!
        System.Diagnostics.Debug.Fail("Undisposed lock");
    }
#endif

Debug.Failの代わりに例外をスローしたい
Pedro77

17

プロジェクトでは、Red GateソフトウェアのAnts Profiler Proを使用しました。すべての.NET言語ベースのアプリケーションで非常にうまく機能します。

.NETガベージコレクターは、メモリ内オブジェクトのクリーンアップにおいて(本来のとおり)非常に「安全」であることがわかりました。なぜなら、私たち将来いつか使用するがある。これは、メモリ内で膨らんだオブジェクトの数についてより注意する必要があることを意味しました。最後に、メモリオーバーヘッドを減らしてパフォーマンスを向上させるために、すべてのデータオブジェクトを「フィールドを要求する直前に」オンデマンドで変換しました。

編集:ここでは、「オンデマンドでの膨張」の意味について詳しく説明します。データベースのオブジェクトモデルでは、親オブジェクトのプロパティを使用して子オブジェクトを公開します。たとえば、他の「詳細」または「ルックアップ」レコードを1対1で参照するレコードがある場合、次のように構成します。

class ParentObject
   Private mRelatedObject as New CRelatedObject
   public Readonly property RelatedObject() as CRelatedObject
      get
         mRelatedObject.getWithID(RelatedObjectID)
         return mRelatedObject
      end get
   end property
End class

上記のシステムでは、メモリに多数のレコードがある場合に、実際のメモリとパフォーマンスの問題が発生することがわかりました。したがって、オブジェクトが要求されたときにのみオブジェクトがインフレートされ、データベース呼び出しが必要なときにのみ行われるシステムに切り替えました。

class ParentObject
   Private mRelatedObject as CRelatedObject
   Public ReadOnly Property RelatedObject() as CRelatedObject
      Get
         If mRelatedObject is Nothing
            mRelatedObject = New CRelatedObject
         End If
         If mRelatedObject.isEmptyObject
            mRelatedObject.getWithID(RelatedObjectID)
         End If
         return mRelatedObject
      end get
   end Property
end class

オブジェクトは、必要になるまで(Getメソッドにアクセスするまで)オブジェクトのメモリから解放されるため、はるかに効率的であることがわかりました。これにより、データベースヒットを制限する際のパフォーマンスが大幅に向上し、メモリ領域が大幅に増加しました。


私はこの製品を2番目にします。これは、私が使用した中で最高のプロファイラーの1つでした。
Gord

プロファイラーはパフォーマンスの問題を調べるのに非常に適していることがわかりました。ただし、メモリ分析ツールはかなり貧弱でした。このツールでリークを発見しましたが、リークの原因を特定するのに役立ちました。また、リークがアンマネージコードにある場合は、まったく役に立ちません。
スコットランガム

新しいバージョン5.1であるOkは、はるかに優れています。リークの原因を特定するのに優れています(ただし、ANTSから次のバージョンで修正されると言われている問題がいくつか残っています)。アンマネージコードはまだ機能しませんが、アンマネージコードを気にしない場合、これは非常に優れたツールです。
スコットランガム、

7

アプリケーションが自明でない限り、マネージコードを作成するときは、メモリについて心配する必要があります。私は2つのことを提案します。最初に、C#を介してCLRを読みます。これは、.NETのメモリ管理を理解するのに役立ちます。次に、CLRProfiler(Microsoft)のようなツールの使い方を学びます。これにより、メモリリークの原因がわかります(たとえば、ラージオブジェクトヒープの断片化を確認できます)。


うん。CLRPRofilerはかなりクールです。割り当てられたオブジェクトを表示するビューを掘り下げようとすると、情報が少し爆発する可能性がありますが、すべてがそこにあります。特に無料であるため、これは間違いなく良い出発点です。
スコットランガム

6

アンマネージコードを使用していますか?Microsoftによると、アンマネージコードを使用していない場合、従来の意味でのメモリリークは不可能です。

ただし、アプリケーションが使用するメモリは解放されない可能性があるため、アプリケーションのメモリ割り当ては、アプリケーションの存続期間を通じて増大する可能性があります。

Microsoft.comで共通言語ランタイムでメモリリークを特定する方法

アプリケーションの一部としてアンマネージコードを使用すると、.NET Frameworkアプリケーションでメモリリークが発生する可能性があります。このアンマネージコードはメモリリークを起こす可能性があり、.NET Frameworkランタイムはその問題に対処できません。

さらに、プロジェクトにはメモリリークがあるように見えるだけです。この状態は、多数のラージオブジェクト(DataTableオブジェクトなど)が宣言され、コレクション(DataSetなど)に追加された場合に発生する可能性があります。これらのオブジェクトが所有するリソースは解放されない可能性があり、リソースはプログラムの実行中ずっと存続します。これはリークのようですが、実際にはプログラムでメモリが割り当てられている方法の症状にすぎません。

このタイプの問題に対処するために、IDisposableを実装できます。メモリ管理に対処するための戦略のいくつかを見たい場合は、IDisposable、XNA、メモリ管理を検索することをお勧めしますゲーム開発者がガベージコレクションをより予測可能にする必要があるため、GCにその処理を強制する必要があるためをします。

よくある間違いの1つは、オブジェクトをサブスクライブするイベントハンドラーを削除しないことです。イベントハンドラーサブスクリプションは、オブジェクトがリサイクルされないようにします。また、リソースの有効期間の限定されたスコープを作成できるusingステートメントを見ください。


5
blogs.msdn.com/tess/archive/2006/01/23/…を参照してください。メモリリークが「従来の」ものであるかどうかは問題ではなく、それでもリークです。
コンスタンティン

2
私はあなたの要点を理解しています-しかし、プログラムによる非効率的なメモリの割り当てと再利用は、メモリリークとは異なります。
ティモシーリーラッセル

良い答えです。イベントハンドラーは危険なものになる可能性があることを思い出していただき、ありがとうございます。
frameworkninja

3
@ティモシー・リー・ラッセル:システム内にタイムリーにルートを解除するために必要な情報と推進力が何もない状態で、役に立たなくなった(2)後、無制限の(1)量のメモリが同時に割り当てられた(ルート化された)ままになる場合、それはメモリリークです。いつかメモリが解放されたとしても、それが発生する前にシステムを詰まらせるのに十分な無駄なものが蓄積される可能性がある場合、それはリークです。(1)O(N)より大きく、Nは有用な割り当て量。(2)スタッフへの参照を削除してもプログラムの機能に影響がない場合、スタッフは役に立たない。
スーパーキャット2018年

2
@ティモシー・リー・ラッセル:通常の「メモリリーク」パターンは、メモリが別のエンティティに代わって 1つのエンティティによって保持され、不要になったときに通知されることを期待しているときに発生しますが、後者は最初のエンティティに通知せずにエンティティを破棄します。メモリを保持するエンティティは実際にはそれを必要としませんが、それを決定する方法はありません。
スーパーキャット2011年

5

このブログには、windbgやその他のツールを使用してすべてのタイプのメモリリークを追跡する、本当に素晴らしいウォークスルーがいくつかあります。あなたのスキルを開発するための優れた読書。


5

Windowsサービスでメモリリークが発生したので、修正しました。

まず、MemProfilerを試しました。私はそれを使用するのは本当に難しく、ユーザーフレンドリーではありませんでした。

次に、使いやすく、正しく配置されていないオブジェクトの詳細を提供するJustTraceを使用しました。

メモリリークを簡単に解決できました。


3

あなたが観察している漏れが暴走キャッシュ実装によるものである場合、これはあなたがシナリオであるかもしれない弱い参照の使用を検討したいです。これは、必要なときにメモリが確実に解放されるようにするのに役立ちます。

ただし、IMHOはオーダーメイドのソリューションを検討する方が良いでしょう。オブジェクトを保持する必要がある期間を本当に知っているのはあなただけなので、状況に応じて適切なハウスキーピングコードを設計することが通常は最善の方法です。


3

Jetbrainsのdotmemoryが好き


あなただけかもしれません:)
HellBaby '15年

私もやってみました。これは良いツールだと思います。使いやすく、有益です。Visual Studioに統合
redeye '22

私たちのケースでは、メモリリークのトラブルシューティングを行っているときに、Visual Studioスナップショットツールがクラッシュしたか、スナップショットが作成されませんでした。Dotmemoryはクールさを保ち、3 GB以上の複数のスナップショットを(見かけ上)簡単に処理しました。
Michael Kargl

3

大きな銃-Windows用デバッグツール

これは素晴らしいツールのコレクションです。マネージヒープとアンマネージヒープの両方を分析でき、オフラインで実行できます。これは、メモリの過剰使用が原因でリサイクルを続けていたASP.NETアプリケーションのデバッグに非常に便利でした。本番サーバーで実行されている生きているプロセスの完全なメモリダンプを作成するだけで、すべての分析はWinDbgでオフラインで行われました。(一部の開発者がメモリ内のセッションストレージを使いすぎていることがわかりました。)

「壊れたら・・・」ブログにはこの件に関する非常に役立つ記事があります。


2

覚えておくべき最良のことは、オブジェクトへの参照を追跡することです。不要になったオブジェクトへの参照がぶら下がってしまうことは非常に簡単です。もう何かを使用しない場合は、それを取り除いてください。

有効期限がスライドするキャッシュプロバイダーの使用に慣れると、目的の時間枠で参照されないものがある場合は、逆参照されてクリーンアップされます。しかし、それが頻繁にアクセスされている場合、それはメモリ内で言うでしょう。


2

最良のツールの1つは、Debugging Tools for Windowsを使用し、adplusを使用してプロセスのメモリダンプを取得してから、windbgを使用することです。し、SOSプロセスメモリ、スレッド、コールスタックを分析するためにプラグインを。

この方法を使用してサーバー上の問題を特定することもできます。ツールのインストール後、ディレクトリを共有し、(net use)を使用してサーバーから共有に接続し、プロセスのクラッシュまたはハングダンプを取得します。

次に、オフラインで分析します。


はい、これは特に、デバッガを簡単に接続できない、より高度なものやリリースされたソフトウェアの問題の診断に適しています。このブログには、これらのツールを上手に使用するための多くのヒントがあります。blogs.msdn.com
スコットランガム

2

管理対象アプリケーションに対する私の修正の1つの後、次の変更後にアプリケーションで同じメモリリークが発生しないことを確認する方法など、同じことがありました。そのため、オブジェクトリリース検証フレームワークのようなものを書きました。 NuGetパッケージObjectReleaseVerification。ここでサンプルを見つけることができますhttps://github.com/outcoldman/OutcoldSolutions-ObjectReleaseVerification-Sample、およびこのサンプルに関する情報http://outcoldman.ru/en/blog/show/322


0

Visual Studio 2015から、すぐに使えるメモリ使用量診断ツール を使用して、メモリ使用量データを収集および分析することを検討してください。

メモリ使用量ツールを使用すると、マネージメモリヒープとネイティブメモリヒープの1つ以上のスナップショットを取得して、オブジェクトタイプのメモリ使用量の影響を理解できます。


0

DotMemoryを使用した最高のツールの1つです。このツールをVSの拡張機能として使用できます。アプリを実行した後、アプリが使用するメモリのすべての部分(オブジェクト、ネームスペースなど)を分析し、そのスナップショットを取得できます。 、他のスナップショットと比較してください。 DotMemory

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.