178

.NETの観点では:

  • メモリリークとは何ですか?
  • アプリケーションがリークしているかどうかをどのように判断できますか?効果は何ですか?
  • どうすればメモリリークを防ぐことができますか?
  • アプリケーションにメモリリークがある場合、プロセスが終了するか強制終了されると、メモリリークはなくなりますか?または、アプリケーションのメモリリークは、プロセスの完了後でもシステム上の他のプロセスに影響を与えますか?
  • また、COM相互運用機能やP/Invokeを介してアクセスされるアンマネージコードについてはどうでしょうか。
4

15 に答える 15

110

私が見た中で最も良い説明は、無料のプログラミングの基礎電子書籍の第7章にあります。

基本的に、.NETでは、参照されるオブジェクトがルート化されるとメモリリークが発生するため、ガベージコレクションを行うことができません。これは、意図した範囲を超えて参照を保持しているときに誤って発生します。

OutOfMemoryExceptionsを取得し始めたとき、またはメモリ使用量が予想を超えたときにリークが発生したことがわかります(PerfMonには優れたメモリカウンターがあります)。

.NETのメモリモデルを理解することは、それを回避するための最良の方法です。具体的には、ガベージコレクターがどのように機能し、参照がどのように機能するかを理解します。ここでも、電子書籍の第7章を参照してください。また、一般的な落とし穴、おそらく最も一般的なイベントであることに注意してください。オブジェクトAがオブジェクトBのイベントに登録されている場合、BはAへの参照を保持しているため、オブジェクトAはオブジェクトBが消えるまで残ります。解決策は、完了したらイベントの登録を解除することです。

もちろん、優れたメモリプロファイルを使用すると、オブジェクトグラフを確認し、オブジェクトのネスト/参照を調べて、参照がどこから来ているのか、どのルートオブジェクトが原因であるのかを確認できます(red-gate antsプロファイル、JetBrains dotMemory、memprofilerは本当に優れています)選択肢、またはテキストのみのWinDbgSOSを使用できますが、本物の第一人者でない限り、商用/ビジュアル製品を強くお勧めします)。

管理されていないコードは、共有参照がガベージコレクターによって管理されていることを除いて、通常のメモリリークの影響を受けやすいと思います。私はこの最後の点について間違っている可能性があります。

于 2008-08-01T15:28:12.543 に答える
35

厳密に言えば、メモリ リークは、プログラムによって「使用されなくなった」メモリを消費しています。

「使用されなくなった」には複数の意味があります。「これ以上参照されない」、つまり完全に回復できないことを意味する場合もあれば、参照されている、回復可能、使用されていないことを意味する場合もありますが、プログラムはとにかく参照を保持します。完全に管理されたオブジェクトの .Net に適用されるのは後者だけです。ただし、すべてのクラスが完璧というわけではなく、ある時点で、基になるアンマネージ実装がそのプロセスのリソースを永久にリークする可能性があります。

いずれの場合も、アプリケーションは必要以上のメモリを消費します。副作用は、漏えい量に応じて、ゼロから過剰な収集によるスローダウン、一連のメモリ例外、そして最後に致命的なエラーに続いて強制的なプロセスの終了に至る可能性があります。

ガベージ コレクション サイクルごとにプロセスに割り当てられるメモリが増えていることを監視が示している場合、アプリケーションにメモリの問題があることがわかります。このような場合、メモリに保持しすぎているか、基になるアンマネージ実装の一部がリークしています。

ほとんどのリークでは、プロセスが終了したときにリソースが回復されますが、一部のリソースは正確なケースでは常に回復されるとは限らず、GDI カーソル ハンドルはそのことで悪名高いです。もちろん、プロセス間通信メカニズムがある場合、他のプロセスで割り当てられたメモリは、そのプロセスが解放するか終了するまで解放されません。

于 2008-08-01T17:52:46.293 に答える
32

「メモリリークとは何か」と「その影響は何か」の質問はすでに十分に回答されていると思いますが、他の質問についてさらにいくつか追加したいと思いました...

アプリケーションがリークしているかどうかを理解する方法

興味深い方法の 1 つは、perfmonを開いて、すべてのヒープ内の # バイト# Gen 2 コレクションのトレースを追加することです。それぞれの場合で、プロセスだけを調べます。特定の機能を実行すると合計バイト数が増加し、そのメモリが次の Gen 2 コレクションの後も割り当てられたままになっている場合、その機能がメモリ リークを起こしていると言えます。

防ぐ方法

他にも良い意見が寄せられています。.NET メモリ リークの最も一般的に見落とされている原因は、オブジェクトを削除せずにオブジェクトにイベント ハンドラーを追加することです。オブジェクトにアタッチされたイベント ハンドラーは、そのオブジェクトへの参照の形式であるため、他のすべての参照がなくなった後でもコレクションを防止します。-=( C#の構文を使用して) イベント ハンドラーをデタッチすることを常に忘れないでください。

プロセスが終了するとリークはなくなりますか? COM 相互運用性はどうですか?

プロセスが終了すると、DLL から提供される COM オブジェクトを含め、そのアドレス空間にマップされたすべてのメモリが OS によって再利用されます。比較的まれに、COM オブジェクトが別のプロセスから提供されることがあります。この場合、プロセスが終了しても、使用した COM サーバー プロセスに割り当てられたメモリを管理する必要があります。

于 2008-08-15T16:11:41.103 に答える
18

.NETのメモリリークを診断する必要がある場合は、次のリンクを確認してください。

http://msdn.microsoft.com/en-us/magazine/cc163833.aspx

http://msdn.microsoft.com/en-us/magazine/cc164138.aspx

これらの記事では、プロセスのメモリダンプを作成する方法とそれを分析して、リークが管理されていないか管理されているかを最初に判断できるようにする方法と、リークが管理されている場合は、リークがどこから来ているのかを把握する方法について説明します。

Microsoftには、クラッシュダンプの生成を支援する、ADPlusに代わる、DebugDiagと呼ばれる新しいツールもあります。

http://www.microsoft.com/downloads/details.aspx?FamilyID=28bd5941-c458-46f1-b24d-f60151d875a3&displaylang=en

于 2008-08-14T23:16:39.803 に答える
18

メモリ リークは、完了後に割り当てられたすべてのメモリを解放しないオブジェクトとして定義します。これは、Windows API と COM (つまり、バグがあるか、正しく管理されていないアンマネージ コード) を使用しているアプリケーション、フレームワーク、およびサード パーティ コンポーネントで発生する可能性があることがわかりました。また、ペンなどの特定のオブジェクトを使用した後に片付けをしないと、問題が発生する可能性があることもわかりました.

私は個人的にメモリ不足の例外に苦しんでいますが、これはドット ネット アプリケーションでのメモリ リークだけが原因ではありません。(OOM はピン留めからも発生する可能性があります。「 Articalのピン留め」を参照してください)。OOM エラーが発生しない場合、または原因がメモリ リークであるかどうかを確認する必要がある場合は、アプリケーションをプロファイリングするしかありません。

また、次のことを確認します。

a) Idisposable を実装するものはすべて、finally ブロックまたは using ステートメントを使用して破棄されます。これには、ブラシ、ペンなどが含まれます (さらに、すべてを何も設定しないと主張する人もいます)。

b) close メソッドを持つものはすべて、finally または using ステートメントを使用して再び閉じられます (ただし、using ステートメントの外側でオブジェクトを宣言したかどうかによって、using が常に閉じるとは限りません)。

c) アンマネージ コード/Windows API を使用している場合、これらは後で正しく処理されます。(リソースを解放するためのクリーンアップ方法があるものもあります)

お役に立てれば。

于 2008-08-01T17:57:14.117 に答える
15

Using CLR Profiler from Microsoft http://www.microsoft.com/downloads/details.aspx?familyid=86ce6052-d7f4-4aeb-9b7a-94635beebdda&displaylang=en is a great way to determine which objects are holding memory, what execution flow leads to the creation of these objects, and also monitoring which objects live where on the heap (fragmentation, LOH, etc.).

于 2008-08-16T19:54:30.497 に答える
14

ガベージ コレクターがどのように機能するかについての最良の説明は、Jeff Richters CLR via C# book (Ch. 20) にあります。これを読むと、オブジェクトがどのように存続するかを理解するための優れた基盤が得られます。

オブジェクトを誤ってルート化する最も一般的な原因の 1 つは、クラスの外でイベントをフックすることです。外部イベントをフックする場合

例えば

SomeExternalClass.Changed += new EventHandler(HandleIt);

破棄するときにフックを外すのを忘れると、 SomeExternalClass にはクラスへの参照があります。

前述のように、SciTech メモリ プロファイラーは、リークが疑われるオブジェクトのルートを示すのに優れています。

しかし、WnDBG を使用するだけで特定のタイプをチェックする非常に簡単な方法もあります (接続中に VS.NET のイミディエイト ウィンドウでこれを使用することもできます)。

.loadby sos mscorwks
!dumpheap -stat -type <TypeName>

次に、そのタイプのオブジェクトを破棄すると思われる何かを実行します (ウィンドウを閉じるなど)。ここで、数回実行されるデバッグ ボタンをどこかに置くと便利ですSystem.GC.Collect()

その後、!dumpheap -stat -type <TypeName>再度実行します。数値が下がらなかった場合、または期待したほど下がらなかった場合は、さらに調査する根拠があります。(このヒントは、 Ingo Rammerによるセミナーから得ました)。

于 2008-08-27T14:12:23.633 に答える
13

管理された環境では、リークは、メモリの大きなチャンクへの不要な参照を保持していることだと思います。

于 2008-08-01T15:19:25.900 に答える
11

.NET のメモリ リークが他のリークと同じではないと人々が考えるのはなぜですか?

メモリ リークは、リソースにアタッチして解放しない場合に発生します。これは、マネージド コーディングとアンマネージド コーディングの両方で行うことができます。

.NET やその他のプログラミング ツールに関しては、ガベージ コレクションや、アプリケーションのリークを引き起こす状況を最小限に抑えるその他の方法についてのアイデアがありました。ただし、メモリ リークを防止する最善の方法は、使用しているプラ​​ットフォームでの基礎となるメモリ モデルと、それがどのように機能するかを理解する必要があることです。

GC やその他の魔法が混乱をクリーンアップすると信じることは、メモリ リークへの近道であり、後で見つけるのが難しくなります。

管理されていないコードをコーディングするときは、通常、必ずクリーンアップを行います。取得したリソースは、用務員ではなく、クリーンアップする責任があることを知っています。

一方、.NET では、多くの人が GC がすべてをクリーンアップすると考えています。まあ、それはあなたのためにいくつかのことをしますが、そうであることを確認する必要があります. .NET は多くのことをラップするため、管理されたリソースを扱っているのか管理されていないリソースを扱っているのかが常にわかるとは限らず、何を扱っているのかを確認する必要があります。フォント、GDI リソース、Active Directory、データベースなどの処理は、通常、注意する必要があるものです。

管理された用語で言えば、プロセスが強制終了/削除されると消えると言うために首をかしげます。

多くの人がこれを持っているのを見ていますが、これが終わることを本当に願っています. 混乱を一掃するためにアプリを終了するようにユーザーに依頼することはできません。IE や FF などのブラウザを見て、たとえば Google リーダーを開き、数日間放置して、何が起こるかを見てください。

次にブラウザで別のタブを開き、あるサイトにアクセスしてから、ブラウザのリークを引き起こした別のページをホストしていたタブを閉じた場合、ブラウザはメモリを解放すると思いますか? IE ではそうではありません。私のコンピューターでは、Google Reader を使用すると、IE は短時間 (約 3 ~ 4 日) で 1 GiB のメモリを簡単に消費します。一部のニュースページはさらに悪い。

于 2008-09-01T12:19:13.210 に答える
9

管理された環境では、メモリの大部分への不要な参照を保持していることがリークになると思います。

絶対。また、必要に応じて破棄可能なオブジェクトで .Dispose() メソッドを使用しないと、メモリ リークが発生する可能性があります。これを行う最も簡単な方法は、最後に .Dispose() を自動的に実行するため、using ブロックを使用することです。

StreamReader sr;
using(sr = new StreamReader("somefile.txt"))
{
    //do some stuff
}

また、アンマネージ オブジェクトを使用するクラスを作成する場合、IDisposable を正しく実装していないと、クラスのユーザーにメモリ リークが発生する可能性があります。

于 2008-08-05T22:47:49.440 に答える
8

すべてのメモリリークは、プログラムの終了によって解決されます。

十分なメモリをリークすると、オペレーティングシステムがユーザーに代わって問題を解決することを決定する場合があります。

于 2008-08-04T14:09:47.117 に答える
7

.netでのmemリークがどうなるかについて、Bernardに同意します。

アプリケーションのプロファイルを作成してメモリの使用状況を確認し、必要のないときに大量のメモリを管理している場合は、リークがあると判断できます。

管理された用語では、プロセスが強制終了/削除されると、それはなくなると言うために首を絞めます。

アンマネージコードはそれ自体が獣であり、その中にリークが存在する場合は、標準のmemに従います。リーク定義。

于 2008-08-01T15:23:33.817 に答える
6

また、.NET には 2 つのヒープがあり、1 つは大きなオブジェクト ヒープであることにも注意してください。おおよそ85k以上のオブジェクトがこのヒープに置かれると思います。このヒープには、通常のヒープとは異なるライフタイム ルールがあります。

大規模なメモリ構造 (辞書またはリスト) を作成している場合は、正確な規則が何であるかを調べるのが賢明です。

プロセスの終了時にメモリを再利用する限り、実行中の Win98 またはそれに相当するものでない限り、終了時にすべてが OS に解放されます。唯一の例外は、クロスプロセスで開かれているもので、別のプロセスがまだリソースを開いているものです。

COM オブジェクトは扱いにくい場合があります。常にIDisposeパターンを使用している場合は、安全です。しかし、実装しているいくつかの相互運用アセンブリに出くわしましたIDispose。ここで重要なのは、Marshal.ReleaseCOMObject作業が終わったら呼び出すことです。COM オブジェクトは、引き続き標準の COM 参照カウントを使用します。

于 2008-08-07T13:17:27.547 に答える
5

.Netでメモリリークを見つけるときに、.Netメモリプロファイラーが非常に役立つことがわかりました。Microsoft CLR Profilerのように無料ではありませんが、私の意見では、より高速で、より重要です。A

于 2008-08-20T18:39:25.953 に答える
1

1 つの定義は次のとおりです。割り当てプロセスの実行中に新しいプロセスに割り当てることができなくなった、到達不能なメモリを解放できません。ほとんどの場合、GC 技術を使用するか、自動化ツールで検出することで解決できます。

詳細については、http://all-about-java-and-weblogic-server.blogspot.in/2014/01/what-is-memory-leak-in-java.htmlを参照してください。

于 2014-08-27T15:22:06.127 に答える