109

この関数をいじることの深刻な意味は理解できますが (または、少なくとも私はそう考えています)、立派なプログラマーが、知らない人でさえも使用しないようなものの 1 つになっている理由がわかりません。それは何のためです。

ユーザーが何をしているかによってメモリ使用量が大きく変化するアプリケーションを開発しているとしましょう。アプリケーションのライフ サイクルは、編集とリアルタイム処理という 2 つの主要な段階に分けることができます。編集段階で、数十億、場合によっては数兆のオブジェクトが作成されるとします。小さいものもあればそうでないものもあり、ファイナライザーを持っているものも持っていないものもあり、それらの寿命は非常に数ミリ秒から長い時間までさまざまであるとします。次に、ユーザーはリアルタイム ステージに切り替えることを決定します。この時点で、パフォーマンスが基本的な役割を果たしており、プログラムの流れのわずかな変更が壊滅的な結果をもたらす可能性があるとします。その後、オブジェクトプールなどを使用してオブジェクトの作成を最小限に抑えますが、GC が予期せず鳴り響いてすべてを破棄し、誰かが死亡します。

質問: この場合、第 2 段階に入る前に GC.Collect() を呼び出すのが賢明ではないでしょうか?

結局のところ、これら 2 つの段階が互いに時間的に重なることはなく、GC が収集できたすべての最適化と統計は、ここではほとんど役に立たないでしょう...

注: ご指摘のとおり、.NET はこのようなアプリケーションに最適なプラットフォームではないかもしれませんが、それはこの質問の範囲を超えています。その意図は、GC.Collect() 呼び出しがアプリケーションの全体的な動作/パフォーマンスを改善できるかどうかを明確にすることです。そのようなことを行う状況が非常にまれであることは誰もが同意しますが、GC は推測を試み、ほとんどの場合は完全にうまくいきますが、それでも推測にすぎません。

ありがとう。

4

20 に答える 20

90

リコのブログから...

ルール#1

しないでください。

これは本当に最も重要なルールです。GC.Collect()のほとんどの使用法は悪い考えであると言っても過言ではありません。元の投稿で詳細に説明したので、ここでは繰り返しません。では、次に進みましょう...

ルール#2

定期的でないイベントが発生したばかりで、このイベントによって多くの古いオブジェクトが停止した可能性が高い場合は、GC.Collect()の呼び出しを検討してください。

この典型的な例は、クライアントアプリケーションを作成していて、大量のデータが関連付けられている非常に大きく複雑なフォームを表示する場合です。ユーザーがこのフォームを操作したばかりで、XMLドキュメントや大きなデータセットなどの大きなオブジェクトが作成される可能性があります。フォームが閉じると、これらのオブジェクトは無効になるため、GC.Collect()はそれらに関連付けられたメモリを再利用します...

したがって、この状況はルール#2に該当する可能性があるように思われます。多くの古いオブジェクトが死んだ瞬間があり、それは再発しません。しかし、リコの別れの言葉を忘れないでください。

ルール#1は、強力な証拠なしにルール#2よりも優先されます。

測定、測定、測定。

于 2008-09-23T02:15:16.947 に答える
58

本番コードでGC.Collect()を呼び出すと、基本的に、GCの作成者よりも多くのことを知っていることを宣言することになります。そうかもしれません。ただし、通常はそうではないため、強くお勧めしません。

于 2008-09-23T01:49:20.160 に答える
26

では、MS Word や MS Excel などの COM オブジェクトを .NET から使用している場合はどうでしょうか。COM オブジェクトを解放した後に呼び出さなくGC.Collectても、Word または Excel アプリケーション インスタンスがまだ存在することがわかりました。

実際に使用するコードは次のとおりです。

Utils.ReleaseCOMObject(objExcel)

' Call the Garbage Collector twice. The GC needs to be called twice in order to get the
' Finalizers called - the first time in, it simply makes a list of what is to be finalized,
' the second time in, it actually does the finalizing. Only then will the object do its 
' automatic ReleaseComObject. Note: Calling the GC is a time-consuming process, 
' but one that may be necessary when automating Excel because it is the only way to 
' release all the Excel COM objects referenced indirectly.
' Ref: http://www.informit.com/articles/article.aspx?p=1346865&seqNum=5
' Ref: http://support.microsoft.com/default.aspx?scid=KB;EN-US;q317109
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

では、ガベージ コレクターの間違った使い方でしょうか? もしそうなら、どうすれば Interop オブジェクトを死なせることができるでしょうか? また、このように使用することを意図していない場合、なぜGC'sCollectメソッドはPublicですか?

于 2012-01-12T15:30:57.230 に答える
16

まあ、GC は私が愛憎関係にあるものの 1 つです。私たちは過去に VistaDB を通じてそれを壊し、それについてブログを書きました。彼らはそれを修正しましたが、このような問題について彼らから修正を得るには長い時間がかかります.

GC は複雑であり、万能型のアプローチでは、これほど大きなものを実現するのは非常に困難です。MS はかなりうまくやっていますが、時々 GC をだますことができます。

Collect一般に、大量のメモリをダンプしたという事実がわかっている場合を除き、a を追加しないでください。GC が今すぐクリーンアップしないと、中年の危機に陥ります。

GC.Collect一連の悪いステートメントでマシン全体を台無しにすることができます。collect ステートメントの必要性は、ほとんどの場合、より大きな根本的なエラーを示しています。メモリ リークは通常、参照と、それらがどのように機能するかについての理解の欠如に関係しています。または、IDisposableそれを必要としない on オブジェクトを使用して、GC にはるかに高い負荷をかけます。

システム パフォーマンス カウンターで GC に費やされた時間の割合を注意深く監視します。アプリが GC で 20% 以上の時間を使用している場合は、深刻なオブジェクト管理の問題 (または異常な使用パターン) があります。アプリ全体の速度が向上するため、GC にかかる時間を常に最小限に抑えたいと考えています。

サーバーとワークステーションでは GC が異なることに注意することも重要です。私は、人々がそれらの両方をテストしていない (またはそれらが 2 つであることさえ認識していない) という、追跡が困難な小さな問題をいくつか見てきました。

そして、私の答えをできるだけ完全にするために、そのプラットフォームもターゲットにしている場合は、Mono でもテストする必要があります。これはまったく異なる実装であるため、MS の実装とはまったく異なる問題が発生する可能性があります。

于 2008-09-23T03:09:26.083 に答える
14

便利な場合もありますが、一般的には避けるべきです。これは、GOTO や原付にたとえることができます。必要なときに行いますが、友人には教えません。

于 2008-09-23T01:39:49.573 に答える
12

私の経験では、実稼働コードで GC.Collect() を呼び出すことはお勧めできません。デバッグでは、はい、潜在的なメモリリークを明確にするのに役立つという利点があります。私の根本的な理由は、GC が私よりもはるかに賢いプログラマーによって作成および最適化されていることであり、GC.Collect() を呼び出す必要があると感じるポイントに到達した場合、それは道から外れたことの手がかりになると思います。どこか。あなたの状況では、実際にメモリの問題があるようには聞こえませんが、コレクションがプロセスにもたらす不安定性を懸念しているだけです。まだ使用中のオブジェクトを一掃することはなく、需要の増加と減少の両方に非常に迅速に適応することを考えると、心配する必要はないと思います.

于 2008-09-23T01:40:58.307 に答える
10

GC.Collect()を呼び出す最大の理由の1つは、説明した内容など、大量のガベージを作成する重要なイベントを実行した直後です。ここでは、GC.Collect()を呼び出すことをお勧めします。そうしないと、GCはそれが「1回限りの」イベントであったことを理解できない可能性があります。

もちろん、プロファイルを作成して、自分の目で確かめてください。

于 2008-09-23T02:07:19.023 に答える
9

明らかに、非リアルタイム ガベージ コレクションを使用する言語で、リアルタイムを必要とするコードを作成するべきではありません。

ステージが明確に定義されている場合、ガベージ コレクターのトリガーに問題はありません。しかし、このケースは非常にまれです。問題は、多くの開発者がこれをカーゴカルト スタイルのペーパーオーバー問題に使用しようとすることであり、無差別に追加するとパフォーマンスの問題が発生します。

于 2008-09-23T01:36:20.423 に答える
7

GC.Collect() を呼び出すと、CLR は強制的にスタック ウォークを実行し、参照をチェックして各オブジェクトを本当に解放できるかどうかを確認します。これは、オブジェクトの数が多い場合にスケーラビリティに影響し、ガベージ コレクションが頻繁にトリガーされることも知られています。CLR を信頼し、必要に応じてガベージ コレクターが自動的に実行されるようにします。

于 2008-09-23T01:55:53.480 に答える
6

実際、GC.Collect を呼び出すことはあまり悪い習慣ではないと思います。
必要な場合もあるかもしれません。たとえば、スレッドを実行するフォームがあり、データベース内のさまざまなテーブルを開き、BLOB フィールドの内容を一時ファイルに抽出し、ファイルを暗号化し、ファイルをバイナリストリームに読み取って BLOB に戻します。別のテーブルのフィールド。

操作全体で大量のメモリが消費され、テーブル内の行数とファイル コンテンツのサイズが不明です。

OutofMemory Exception が頻繁に発生していたので、カウンター変数に基づいて GC.Collect を定期的に実行するのが賢明だと考えました。カウンターをインクリメントし、指定されたレベルに達すると、GC が呼び出されて、形成された可能性のあるガベージを収集し、予期しないメモリ リークのために失われたメモリを回収します。

この後、少なくとも例外なく、うまく機能していると思います!!!
私は次の方法で呼び出します。

var obj = /* object utilizing the memory, in my case Form itself */
GC.Collect(GC.GetGeneration(obj ,GCCollectionMode.Optimized).
于 2013-03-20T15:20:24.210 に答える
5

ループで画像を作成する - dispose を呼び出しても、メモリは回復されません。ガベージコレクションは毎回行います。写真処理アプリのメモリが 1.7GB から 24MB になりましたが、パフォーマンスは優れています。

GC.Collect を呼び出す必要がある時間は絶対にあります。

于 2012-10-22T20:52:34.957 に答える
5

.net では、ガベージ コレクションの実行に必要な時間は、ガベージの量よりも、ガベージではないものの量に大きく関係しています。実際、オブジェクトがFinalize(明示的に、または C# デストラクタを介して) オーバーライドするか、 のターゲットであるWeakReferenceか、Large Object Heap に置かれているか、またはその他の gc 関連の方法で特別でない限り、オブジェクトが置かれているメモリを識別する唯一のものは、オブジェクトであることは、それへのルート化された参照の存在です。それ以外の場合、GC の操作は、建物からすべての価値のあるものを取り出し、その建物をダイナマイトで破壊し、古い建物の場所に新しい建物を建設し、すべての貴重なアイテムをそこに置くことに似ています。建物をダイナマイトするのに必要な労力は、建物内のゴミの量とはまったく関係ありません。

その結果、呼び出しGC.Collectは、システムが実行しなければならない作業の全体量を増加させる傾向があります。次のコレクションの発生を遅らせますが、次のコレクションが発生したときに必要だったのと同じ量の作業をすぐに実行する可能性があります。次のコレクションが発生した時点で、収集に費やされた合計時間は、呼び出されていなかった場合とほぼ同じになりますが、システムにガベージが蓄積されているため、次のコレクションが呼び出されなかっGC.Collectた場合よりも早く必要になります。GC.Collect呼ばれました。

私がGC.Collect実際に役立つのは、一部のコードのメモリ使用量を測定する必要がある場合 (メモリ使用量の数値はコレクションの後にのみ意味があるため)、またはいくつかのアルゴリズムのうちどれが優れているかをプロファイルする必要がある場合です (GC.Collect() を呼び出します)。コードのいくつかの部分をそれぞれ実行する前に、一貫したベースライン状態を確保するのに役立ちます)。GC が知らないことを知っているかもしれない他のいくつかのケースがありますが、シングルスレッドのプログラムを書いていない限り、あるGC.Collectスレッドのデータ構造が「ミッドライフ クライシス」を回避するのに役立つ呼び出しを知る方法はありません。他のスレッドのデータに「中年の危機」が発生することはありません。

于 2012-05-13T16:31:56.990 に答える
4

ガベージ コレクターがガベージを収集せず、メモリを解放するという同様の問題がありました。

私たちのプログラムでは、OpenXML を使用して適度なサイズの Excel スプレッドシートを処理していました。スプレッドシートには、14 列の約 1000 行の「シート」が 5 ~ 10 枚含まれていました。

32 ビット環境 (x86) のプログラムは、「メモリ不足」エラーでクラッシュします。x64 環境で実行することはできましたが、より優れたソリューションが必要でした。

1つ見つかりました。

破棄されたオブジェクトからメモリを解放するためにガベージ コレクターを明示的に呼び出した場合に、機能しなかったコードと機能したコードの一部を簡単に示します。

サブルーチン内から GC を呼び出しても機能しませんでした。メモリは再利用されませんでした...

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
End Sub

GC 呼び出しをサブルーチンの範囲外に移動することで、ガベージが収集され、メモリが解放されました。

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
End Sub

への呼び出しを無視しているように見える .NET ガベージ コレクションに不満を感じている他のユーザーに、これが役立つことを願っていますGC.Collect()

ポールスミス

于 2014-02-05T15:32:01.893 に答える
2

最悪の場合、プログラムが少しフリーズします。ですから、それでよければ、それを実行してください。通常、ほとんどのユーザー操作を伴うシッククライアントまたはWebアプリには必要ありません。

実行時間の長いスレッドを持つプログラム、またはバッチプログラムでは、オブジェクトを適切に処理していても、OutOfMemory例外が発生することがあります。私が思い出したのは、基幹業務データベースのトランザクション処理でした。もう1つは、シッククライアントアプリのバックグラウンドスレッドでのインデックス作成ルーチンでした。

どちらの場合も、結果は単純でした。GC.Collectがなく、メモリ不足で、一貫して。GC.Collect、完璧なパフォーマンス。

私はそれを他の数回メモリの問題を解決するために試しましたが、役に立ちませんでした。取り出しました。

つまり、エラーが発生しない限り、入れないでください。入れてもメモリの問題が解決しない場合は、取り出してください。リリースモードでテストし、リンゴとリンゴを比較することを忘れないでください。

これで物事がうまくいかないのは、道徳的になるときだけです。これは値の問題ではありません。多くのプログラマーが亡くなり、多くの不必要なGCを使って天国に直行しました。コードを収集することで、長生きします。

于 2012-08-17T01:19:25.740 に答える
2

どうしたの?ガベージ コレクターとメモリ アロケーターを推測しているという事実は、実行時のアプリケーションの実際のメモリ使用量について、実際よりもはるかに優れています。

于 2008-09-24T23:14:29.157 に答える
2

GC.Collect() を呼び出したいという欲求は、通常、どこかで犯した間違いを隠蔽しようとしています!

不要になったものを捨てるのを忘れた場所を見つけられるとよいでしょう。

于 2008-10-19T17:23:38.450 に答える
2

シナリオについては正しいと思いますが、API についてはわかりません。

Microsoft は、このような場合、GC がすぐにコレクションを実行するように、GC にヒントとしてメモリ プレッシャを追加する必要があると述べています。

于 2008-09-23T01:33:56.093 に答える
1

.NET Framework自体は、リアルタイム環境で実行するように設計されたことはありません。本当にリアルタイム処理が必要な場合は、.NETに基づかない埋め込みリアルタイム言語を使用するか、WindowsCEデバイスで実行されている.NETCompactFrameworkを使用します。

于 2008-09-23T03:25:24.187 に答える
1

つまり、アプリケーションをプロファイリングして、これらの追加のコレクションがどのように影響するかを確認できます。ただし、プロファイルを作成する場合を除き、近づかないことをお勧めします。GC はそれ自体を処理するように設計されており、ランタイムが進化するにつれて、効率が向上する可能性があります。作業を台無しにして、これらの改善を利用できなくなる可能性のあるコードがぶらぶらしているのは望ましくありません。for の代わりに foreach を使用することについても、同様の議論があります。つまり、今後の内部改良を foreach に追加することができ、それを利用するためにコードを変更する必要がないということです。

于 2008-09-23T01:41:38.070 に答える