なぜSystem.gc()を呼び出すのが悪い習慣なのですか?


326

Javaでオブジェクト強制的に解放する方法についての質問に答えた後(男は1.5GBのHashMapをクリアしていました)、手動で呼び出すのは悪い習慣だと言われましたが、コメントは完全には説得力がありませんでした。さらに、私の回答に賛成票を投じたり、反対票を投じたりする人はいなかったようです。System.gc()System.gc()

そこは悪い習慣だと言われましたが、ガベージコレクターの実行によって世界が体系的に停止することはなく、JVMがヒントとしてのみ効果的に使用できることも伝えられたので、途方に暮れる。

通常、JVMがメモリを再利用する必要がある場合、JVMはあなたよりもよく知っていることは理解しています。また、数キロバイトのデータを心配するのはばかげていることも理解しています。メガバイトのデータでさえ、数年前のデータではないことも理解しています。しかし、それでも1.5ギガバイトですか?そして、あなたは知っているメモリにぶらぶらデータの1.5ギガバイトのようにあります。それは暗闇の中でのショットのようではありません。でSystem.gc()体系的に悪い、またはそれは大丈夫になった時に、いくつかのポイントがありますか?

したがって、質問は実際には二重です:

  • なぜ電話をするのが悪いのSystem.gc()ですか?それは本当に特定の実装でのJVMへのヒントにすぎないのですか、それとも常に完全な収集サイクルですか?世界を止めることなく作業を実行できるガベージコレクターの実装は本当にありますか?私の回答へのコメントで人々が行ったさまざまな主張にいくつかの光を当ててください。
  • しきい値はどこですか?を呼び出すのは良い考えではありませんSystem.gc()か、それとも許容できる場合がありますか?もしそうなら、それらの時間は何ですか?

4
System.gc()を呼び出す良いタイミングは、すでに長いロードプロセスである何かを実行しているときだと思います。たとえば、私はゲームに取り組んでいて、ゲームが新しいレベルをロードするときに、ロードプロセスの最後にSystem.gc()を呼び出すことを計画しています。ユーザーはすでに少し待っており、追加のパフォーマンス向上はそれだけの価値があるかもしれません。ただし、この動作を無効にするオプションも構成画面に配置します。
Ricket

41
Bozho:質問の最初の言葉に注意してください。なぜそれを呼び出さないのがベストプラクティスなのですか?マントラを繰り返すだけでは、のろわれた事柄は説明されません。
私の正しい意見2010年

1
別のケースは、java-monitor.com / forum / showthread.phpt = 188で説明されてい ます。ここでは、System.gc()を呼び出すのが悪い習慣である可能性があることを説明しています
Shirishkumar Bari

回答:


243

誰もが常に避けようとする理由System.gc()は、それが根本的に壊れたコードのかなり良い指標であることです。正確さを求めてそれに依存するコードは確実に破られます。パフォーマンスに依存しているものは、おそらく壊れています。

どのようなガベージコレクターを実行しているかはわかりません。あなたが主張するように「世界を止める」ことができないものも確かにありますが、JVMの中にはそれほどスマートではない、またはさまざまな理由で(おそらく彼らは電話にいるのでしょうか?)それを行わないものもあります。あなたはそれが何をするのか分からない。

また、何も保証されていません。JVMはリクエストを完全に無視する場合があります。

「何をするかわからない」「助けになるかどうかわからない」「とにかく呼んではいけない」の組み合わせが、あなたはそれを呼ぶべきではありません。「これを使うべきかどうかを尋ねる必要があるなら、使うべきではない」のケースだと思います


他のスレッドからのいくつかの懸念に対処するための編集

リンクしたスレッドを読んだ後、指摘したいことがいくつかあります。最初に、誰かが呼び出しgc()がシステムにメモリを戻すかもしれないことを誰かが提案しました。それは確かに必ずしも真実ではありません-Javaヒープ自体はJavaの割り当てとは関係なく成長します。

同様に、JVMはメモリ(数十メガバイト)を保持し、必要に応じてヒープを拡張します。Javaオブジェクトを解放しても、そのメモリがシステムに返されるとは限りません。将来のJava割り当てに使用するために、割り当てられたメモリを保持することは完全に自由です。

System.gc()何もしないことが可能であることを示すには、次を表示します。

http://bugs.sun.com/view_bug.do?bug_id=6668279

特に-XX:DisableExplicitGC VMオプションがあります。


1
GCを実行するメソッドがコードの正確さに影響する奇妙なRube Goldberg風のセットアップを構築できる場合があります。おそらく、奇妙なスレッドの相互作用を覆い隠しているか、ファイナライザがプログラムの実行に大きな影響を与えている可能性があります。それが可能かどうかは完全にはわかりませんが、可能かもしれないので、私はそれについて言及したいと思いました。
Steven Schlansker、2010年

2
@zneakたとえば、重要なコードをファイナライザに挿入した可能性があります(これは基本的に壊れたコードです)
Martin

3
いくつかのコーナーケースSystem.gc()が便利であり、必要な場合もあることを付け加えておきます。たとえば、WindowsのUIアプリケーションでは、ウィンドウを最小化する前に System.gc()を呼び出すと、ウィンドウの復元プロセスが大幅に高速化されます(特に、ウィンドウがかなり最小化されたままで、プロセスの一部がスワップされる場合)。ディスク)。
Joachim Sauer

2
@AndrewJanke WeakReference保持したいオブジェクトにsを使用するコードは、ガベージコレクションの有無にかかわらず、最初から正しくないと思います。C ++でも同じ問題std::weak_ptrが発生します(ただし、C ++バージョンではJavaバージョンよりも早く問題が発生する可能性があります。オブジェクトの破棄はファイナライズのように遅延されないためです)。
JAB 2014

2
@rebeccahそれはバグなので、はい、私はそれを「確かに壊れている」と呼びます。System.gc()それを修正するという事実は回避策であり、良いコーディング方法ではありません。
Steven Schlansker 2014年

149

呼び出しsystem.gc() によって実行されない可能性があること、およびガベージコレクターの実行を「必要」とするコードが壊れていることはすでに説明されています。

ただし、呼び出すのSystem.gc()が悪い習慣であるという実際的な理由は、効率が悪いためです。そして最悪の場合、それはひどく非効率的です!説明させてください。

典型的なGCアルゴリズムは、ヒープ内のすべてのガベージ以外のオブジェクトをトラバースし、アクセスされていないオブジェクトはガベージでなければならないと推論することによって、ガベージを識別します。このことから、ガベージコレクションの総作業量は、ライブデータの量に比例する1つの部分と、ガベージの量に比例する別の部分で構成されるモデルを作成できます。すなわちwork = (live * W1 + garbage * W2)

ここで、シングルスレッドアプリケーションで次のことを行ったとします。

System.gc(); System.gc();

最初の呼び出しは(予測)機能し(live * W1 + garbage * W2)、未処理のゴミを取り除きます。

2番目の呼び出しは(live* W1 + 0 * W2)機能し、何も再生しません。言い換えれば、私たちは(live * W1)仕事をして、まったく何も達成しませんでした

コレクターの効率は、ごみの単位を収集するために必要な作業量としてモデル化できます。すなわちefficiency = (live * W1 + garbage * W2) / garbage。したがって、GCを可能な限り効率的にするために、GC を実行するときの価値を最大化する必要がありgarbageます。つまり、ヒープがいっぱいになるまで待ちます。(また、ヒープをできるだけ大きくします。ただし、これは別のトピックです。)

アプリケーションが(を呼び出すことによりSystem.gc())干渉しない場合、GCは実行前にヒープがいっぱいになるまで待機するため、ガーベッジ1が効率的に収集されます。ただし、アプリケーションが強制的にGCを実行する場合、ヒープがいっぱいにならない可能性があり、その結果、ガベージが非効率的に収集されます。アプリケーションが頻繁にGCを強制するほど、GCの効率は低下します。

注:上記の説明は、典型的な最新のGCがヒープを「スペース」に分割すること、GCが動的にヒープを拡張すること、アプリケーションの非ガベージオブジェクトのワーキングセットが異なることなどを示しています。それでも、同じ基本原則がすべての真のガベージコレクター2に適用されます。GCを強制的に実行するのは非効率的です。


1-これが「スループット」コレクターの動作方法です。CMSやG1などの並行コレクターは、さまざまな基準を使用して、ガベージコレクターを開始するタイミングを決定します。

2-参照カウントのみを使用するメモリマネージャーも除外していますが、現在のJava実装ではそのアプローチを使用していません...正当な理由があります。


45
+1良い説明。ただし、この推論はスループットを重視する場合にのみ適用されることに注意してください。特定の時点で潜在性を最適化したい場合は、GCを強制することは意味があります。たとえば、ゲームで(仮説的に言えば)レベル中の遅延を避けたいかもしれませんが、レベルの読み込み中の遅延は気にしません。その場合、レベルのロード後にGCを強制することは意味があります。全体的なスループットは低下しますが、それは最適化するものではありません。
sleske

2
@sleske-あなたの言うことは真実です。ただし、レベル間でGCを実行することはバンドエイドソリューションであり、レベルがとにかくレベル中にGCを実行する必要があるほど時間がかかる場合、レイテンシの問題は解決しません。より良いアプローチは、プラットフォームがサポートしている場合は、同時(低休止)ガベージコレクターを使用することです。
スティーブンC

「ガベージコレクタを実行する必要がある」という意味が完全にわかりません。アプリケーションが回避する必要がある条件は次のとおりです。決して満足できない割り当ての失敗と高いGCオーバーヘッド。System.gc()をランダムに呼び出すと、GCのオーバーヘッドが高くなることがよくあります。
Kirk 14

@Kirk- 「ランダムにSystem.gc()を呼び出すと、GCオーバーヘッドが高くなることがよくあります。」。そんなこと知ってる。だから私の答えを読んで理解した人なら誰でもそうだろう。
スティーブンC

@Kirk- 「意味がわからない...」 -プログラムの「正しい」動作が特定の時間に実行されるGCに依存するプログラムを意味します。たとえば、ファイナライザを実行したり、WeakReferencesやSoftReferencesを壊したりするためです。これを行うのは本当に悪い考えです...しかし、これは私が話していることです。Steven Schlanskerの回答も参照してください。
スティーブンC

47

多くの人がこれをしないように言っているようです。同意しません。レベルのロードなどの大規模なロードプロセスの後で、次のように考えている場合:

  1. 到達できないオブジェクトが多数あり、GCされていない可能性があります。そして
  2. この時点でユーザーは少しの減速に耐えられると思います

System.gc()を呼び出しても害はありません。私はそれをc / c ++ inlineキーワードのように見ています。開発者であるあなたが時間/パフォーマンスは通常ほど重要ではなく、その一部をメモリの解放に使用できると判断したことは、GCへのヒントにすぎません。

何かをすることに依存しないというアドバイスは正しいです。それが機能していることに依存しないでください。ただし、今が収集に許容できる時間であるというヒントを与えることは完全に問題ありません。ユーザーがプログラムをアクティブに操作しているとき(ゲームのレベルの間など)よりも、コードの重要ではない時点(読み込み画面)で時間を無駄にしたいと思います。

コレクションを強制するときがあります:特定のオブジェクトリーク(ネイティブコードまたは大規模で複雑なコールバックの相互作用のいずれかです。ああ、Matlabを一目見ただけのUIコンポーネント)を見つけようとすると、これは使用しないでください生産コードで。


3
メモリリークの分析中のGCの+1。ヒープ使用量に関する情報(Runtime.freeMemory()など)は、GCを強制した後でのみ意味があることに注意してください。それ以外の場合、システムが最後にGCを実行する必要があったときに依存します。
sleske 2010

4
System.gc()の呼び出しに害はありません。stop the worldアプローチが必要な場合があり、これが発生した場合、これは実際の害です
bestsss

7
ガベージコレクターを明示的に呼び出すことに害があります。間違った時間にGCを呼び出すと、CPUサイクルが無駄になります。あなた(プログラマー)には、適切なタイミングがいつであるかを判断するのに十分な情報がありません...しかし、JVMはそうです。
スティーブンC

Jettyは起動後にSystem.gc()を2回呼び出しますが、違いが見られることはほとんどありません。
カーク14

まあ、Jetty開発者にはバグがあります。違いを定量化するのが難しい場合でも、違いが生じます。
スティーブンC

31

人々はなぜ使用しないのかを説明する良い仕事をしているので、それを使用すべきいくつかの状況を説明します。

(以下のコメントは、CMSコレクターを備えたLinux上で実行されているHotspotに適用されますSystem.gc()。実際には常にフルガベージコレクションを呼び出すと私が確信していると私は確信しています)。

  1. アプリケーションを起動する最初の作業の後、メモリ使用量がひどい状態になる可能性があります。在職世代の半分がゴミでいっぱいになる可能性があります。つまり、あなたは最初のCMSに非常に近いということです。それが重要なアプリケーションでは、System.gc()を呼び出してヒープをライブデータの開始状態に「リセット」することは悪い考えではありません。

  2. #1と同じように、ヒープの使用状況を注意深く監視している場合は、ベースラインのメモリ使用量を正確に読み取る必要があります。アプリケーションの稼働時間の最初の2分間がすべて初期化である場合、完全なgcを前もって強制(ahem ... "suggest")しない限り、データはめちゃくちゃになります。

  3. 実行中の世代に何も昇格しないように設計されたアプリケーションがあるかもしれません。ただし、場合によっては、自動的に古い世代に移動するほど大きくないデータを事前に初期化する必要があります。すべてが設定された後にSystem.gc()を呼び出さない限り、昇格する時が来るまで、データは新世代にとどまることができます。突然、すべてのスーパーデューパーの低レイテンシ、低GCアプリケーションは、通常の操作中にこれらのオブジェクトを昇格させるために、(当然のことながら、)大きなレイテンシペナルティに見舞われます。

  4. メモリリークの存在を確認するために、運用アプリケーションでSystem.gc呼び出しを使用できると便利な場合があります。時間Xのライブデータのセットが時間Yのライブデータのセットに対して特定の比率で存在する必要があることがわかっている場合、System.gc()を時間Xと時間Yに呼び出して、メモリ使用量を比較すると便利です。 。


1
ほとんどの世代のガベージコレクターでは、新しい世代のオブジェクトは特定の(多くの場合、構成可能な)ガベージコレクションの数を超えて生き残る必要があるため、System.gc()オブジェクトの昇格を強制するために一度呼び出すと何も得られません。そしてSystem.gc()、8回続けて電話をかけて祈らないようにしてください。今は昇格が行われ、後の昇格の節約されたコストは複数のフルGCのコストを正当化します。GCアルゴリズムによっては、メモリを古い世代またはコピーに同時に再割り当てするだけなので、多くのオブジェクトをプロモートしても実際のコストはかかりません…
ホルガー

11

これは非常に面倒な質問であり、言語がいかに有用であるにも関わらず、Javaに反対する多くの人に貢献していると感じています。

「System.gc」が何かを実行することを信頼できないという事実は非常に困難であり、「恐怖、不確実性、疑い」の感覚を言語に簡単に呼び出すことができます。

多くの場合、重要なイベントが発生する前に故意に引き起こしたメモリスパイクに対処すると、ユーザーがプログラムの設計が不適切で応答がないと考えるようになります。

ガベージコレクションを制御する機能は非常に優れた教育ツールとなり、ガベージコレクションのしくみとプログラムがデフォルトの動作と制御された動作をどのように利用するかを人々に理解を深めることができます。

このスレッドの引数を確認しましょう。

  1. それは非効率的です:

多くの場合、プログラムは何も実行していない可能性があり、プログラムの設計方法が原因で何も実行していないことがわかります。例えば、それは大きな待機メッセージボックスである種の長い待機を行っているかもしれません、そしてそれを実行する時間は本当に時間のほんのわずかな時間しかかからないので、最後にそれはガベージを収集するための呼び出しを追加するかもしれません。長時間待機しますが、より重要な操作の途中でgcが機能しなくなります。

  1. これは常に悪い習慣であり、コードが壊れていることを示しています。

私は同意しません、あなたがどんなガベージコレクタを持っているかは問題ではありません。その仕事はゴミを追跡し、それをきれいにすることです。

使用がそれほど重要ではない時間帯にgcを呼び出すことにより、実行中の特定のコードに依存しているが、ガベージを収集することを決定した場合に、実行される確率を減らすことができます。

もちろん、期待どおりまたは期待どおりに動作しない場合がありますが、呼び出したい場合は、何も起こっていないことがわかり、ユーザーは遅延やダウンタイムを許容します。System.gcが機能すれば、すばらしいです。そうでない場合、少なくともあなたは試しました。ガベージコレクターに、ガベージコレクターが手動で呼び出された場合の動作を想定した場合に予期せぬ事態を招くような固有の副作用がない限り、不都合な点はありません。

  1. これは一般的なユースケースではありません:

これは確実に達成できないユースケースですが、システムがそのように設計されている場合はそうなる可能性があります。それは信号機を作り、信号機のボタンの一部/すべてが何もしないようにすることのようなものです、それはなぜボタンがそもそもそこにあるのか疑問に思います、JavaScriptはガベージコレクション機能を持っていないので私たちはしませんあまり精査しないでください。

  1. 仕様によると、System.gc()はGCを実行するためのヒントであり、VMはそれを自由に無視できます。

「ヒント」とは何ですか?「無視」とは何ですか?コンピュータは単にヒントを受け取ったり、何かを無視したりすることはできません。システムの意図によって導かれる、動的である可能性のある厳密な動作パスがあります。適切な答えには、ガベージコレクターが実装レベルで実際に何をしているかが含まれます。これにより、要求時にコレクションが実行されなくなります。機能は単にnopですか?満たさなければならない条件はありますか?これらの条件は何ですか?

現状では、JavaのGCは、あなたが信用していないモンスターのように見えることがよくあります。あなたはそれがいつ来るのか、いつ行くのか、あなたはそれが何をするのか、どうやってそれをするのかを知りません。ガベージコレクションが命令ごとにどのように機能するかについてより良いアイデアを持っている一部の専門家を想像できますが、大多数は単に「正しく機能する」ことを望んでおり、不透明に見えるアルゴリズムを信頼して仕事をするのはイライラさせられます。

何かについて読んだり、教えられたりすることと、実際にその実装を確認すること、システム全体の違いを理解すること、そしてソースコードを見なくてもそれを試すことができることの間には大きなギャップがあります。これは自信と習得/理解/コントロールの感覚を生み出します。

要約すると、答えには固有の問題があります。「この機能は何も実行しない可能性があります。また、実行するタイミングと実行しないタイミング、および実行しない、または実行しない理由を詳細に説明することはしません。それをしようとすることは、その背後にある意図が合理的であるとしても、単にそれをしようとする哲学に反していることをしばしば意味します。」

Java GCがそのように動作することは問題ないかもしれませんが、そうでない場合もありますが、それを理解するために、GCが信頼できることの包括的な概要を取得するためにどの方向に進むかを正確に追跡することは困難です。そうしないと、言語の目的が哲学的な範囲まで行動を制御することであるので、言語を単純に信用するのは簡単です(プログラマー、特に初心者が特定のシステム/言語の行動から実存的危機に陥るのは簡単です)。許容する能力があり(できない場合は、必要になるまでその言語を使用しません)、それらを制御できない既知の理由がないために制御できないものは本質的に有害です。


9

GCの効率は多くのヒューリスティックに依存しています。たとえば、一般的なヒューリスティックは、オブジェクトへの書き込みアクセスは通常、それほど前に作成されていないオブジェクトで発生するというものです。もう1つは、多くのオブジェクトの寿命が非常に短いことです(一部のオブジェクトは長期間使用されますが、多くのオブジェクトは作成後数マイクロ秒で破棄されます)。

呼び出しSystem.gc()は、GCをキックするようなものです。つまり、「これらの注意深く調整されたすべてのパラメーター、スマートな組織、オブジェクトの割り当てと管理に費やしたすべての労力により、物事は円滑に順調に進行し、ロット全体をドロップし、ゼロから始めます」。それはあり、パフォーマンスを向上させるが、それはただの時間のほとんど劣化させるパフォーマンスを。

System.gc()確実に使用するには(*)、GCが細部にわたってどのように動作するかを知る必要があります。このような詳細は、別のベンダーのJVM、または同じベンダーの次のバージョン、または同じJVMを使用するが、コマンドラインオプションがわずかに異なる場合、かなり変化する傾向があります。したがって、これらのすべてのパラメーターを制御する特定の問題に対処したい場合を除いて、それが推奨されることはめったにありません。したがって、「悪い習慣」の概念:これは禁止されていません。この方法は存在しますが、ほとんど効果がありません。

(*)ここでは効率について話しています。正しいJavaプログラムが壊れるSystem.gc()ことは決してありません。JVMが他の方法で取得できなかった余分なメモリを呼び出すこともありません。をスローする前に、JVMはのジョブを実行します(最後の手段としても)。OutOfMemoryErrorSystem.gc()


1
System.gc()がOutOfMemoryErrorを防止しないことを言及するための+1。一部の人々はこれを信じています。
sleske 2010

1
実際には、ソフト参照の処理のため、OutOfMemoryErrorを防ぐことできます。最後のGC実行後に作成されたSoftReferencesは、私が知っている実装では収集されません。しかし、これはいつでも変更される可能性がある実装の詳細であり、一種のバグであり、信頼すべきものは何もありません。
maaartinus '25年

8

時々(それほど頻繁ではありませんが!)、実行時よりも過去、現在、および将来のメモリ使用量について本当に知っています。これはそれほど頻繁には発生せず、通常のページが提供されている間は、Webアプリケーションでは絶対に要求しないでしょう。

何年も前に、私はレポートジェネレーターに取り組んでいます。

  • シングルスレッドがあった
  • キューから「レポートリクエスト」を読み取る
  • データベースからレポートに必要なデータをロードしました
  • レポートを生成してメールで送信した。
  • 永久に繰り返され、未解決の要求がないときに眠っています。
  • レポート間でデータを再利用したり、キャッシングを行ったりすることはありませんでした。

まず、リアルタイムではなく、ユーザーがレポートを待つことを期待していたため、GCの実行中に問題が発生することはありませんでしたが、要求よりも速い速度でレポートを作成する必要がありました。

上記のプロセスの概要を見ると明らかです。

  • 次のリクエストの処理がまだ開始されていないため、レポートがメールで送信された直後は、ライブオブジェクトはほとんどありません。
  • ガベージコレクションサイクルを実行するコストはライブオブジェクト数に依存することはよく知られています。ガベージの量はGC実行のコストにほとんど影響しません。
  • キューが空の場合は、GCを実行することをお勧めします。

したがって、リクエストキューが空のときはいつでもGCを実行している間、それは明らかに価値がありました。これには欠点はありませんでした。

これはGC実行に適したタイミングであることがわかっているため、各レポートが電子メールで送信された後、GC実行を実行する価値があります。ただし、コンピューターに十分なRAMがある場合は、GCの実行を遅らせることにより、より良い結果が得られます。

この動作は、インストールごとに構成されました。一部のお客様は、各レポートがレポートの保護を大幅に高速化した後に強制GCを有効にしました。(これは、サーバーのメモリが少なく、他の多くのプロセスが実行されているためだと思います。そのため、十分な時間の強制GCによってページングが減少しました。)

ワークキューが空になるたびに強制GCが実行されるというメリットがないインストールは検出されませんでした。

ただし、明確にしておくと、上記は一般的なケースではありません。


3

多分私は安っぽいコードを書いていますが、EclipseとNetBeans IDEのゴミ箱アイコンをクリックすることは「良い習慣」であることに気づきました。


1
これはそうかもしれません。しかし、EclipseまたはNetBeansがSystem.gc()定期的に呼び出されるようにプログラムされている場合、おそらくその動作は煩わしいものになるでしょう。
スティーブンC

2

まず、スペックと現実には違いがあります。仕様によると、System.gc()はGCを実行するためのヒントであり、VMはそれを自由に無視できます。実際には、VMがSystem.gc()の呼び出しを無視することはありません

GCを呼び出すと、呼び出しにかなりのオーバーヘッドがかかります。ランダムな時点でこれを行うと、努力に対して報酬が得られない可能性があります。一方、自然にトリガーされるコレクションは、呼び出しのコストを取り戻す可能性が非常に高くなります。GCを実行する必要があることを示す情報がある場合は、System.gc()を呼び出すことができますが、利点がわかります。ただし、System.gc()を呼び出す必要があるかどうか、またいつ呼び出す必要があるかを理解するのに十分な情報が得られる可能性は非常に低いため、これは少数のエッジケースでのみ発生するというのが私の経験です。

ここにリストされている1つの例は、IDEでゴミ箱にアクセスすることです。会議に参加する場合は、打ち合わせをしてみませんか。オーバーヘッドはあなたに影響を与えるつもりはなく、戻ったときにヒープがクリーンアップされるかもしれません。本番システムでこれを行うと、収集を頻繁に呼び出すと、停止することになります。RMIによって行われるような時折の呼び出しでさえ、パフォーマンスを破壊する可能性があります。


3
「実際には、VMがSystem.gc()の呼び出しを無視することはありません。」 -不正解。-XX:-DisableExplicitGCについてお読みください。
スティーブンC

1

はい、System.gc()を呼び出しても、実行が保証されるわけではなく、無視される可能性があるJVMへの要求です。ドキュメントから:

gcメソッドの呼び出しは、Java仮想マシンが未使用のオブジェクトのリサイクルに労力を費やすことを示唆しています

自動メモリ管理は通常、いつgcを実行するかを知っているので、ほとんどの場合それを呼び出すのは悪い考えです。これは、空きメモリの内部プールが少ない場合、またはOSが一部のメモリの返送を要求した場合に行われます。

役立つことがわかっている場合は、System.gc()を呼び出してもかまいません。つまり、展開プラットフォームでの両方のシナリオの動作を徹底的にテストおよび測定し、それが役立つことを示すことができます。ただし、GCは簡単には予測できないので注意してください。ある実行で役立ち、別の実行では害を及ぼす可能性があります。


<stroke>しかし、Javadocからも:_メソッド呼び出しから制御が戻ったとき、仮想マシンは、破棄されたすべてのオブジェクトをリサイクルするために最善を尽くしました。これは、あなたが投稿したもののより必須の形式であると私は思います。</ stroke >誤解を招く、誤解を招くバグレポートがあります。JVMにヒントを与えることの害は何ですか?
zneak

1
害は、間違った時間に収集を行うと、大幅に遅くなる可能性があることです。あなたが与えているヒントはおそらく悪いものです。「ベストエフォート」のコメントについては、JConsoleなどのツールで試してみてください。「Perform GC」ボタンをクリックしても何も起こらない場合があります
tom

申し訳ありませんが、OpenJDKでSystem.gc()とそれに基づくもの(HPなど)を呼び出すと、常にガベージコレクションサイクルが発生します。実際、これはIBMのJ9実装にも当てはまるようです
Kirk

@カーク-不正解:グーグル、そして-XX:-DisableExplicitGCについて読んでください。
スティーブンC

0

私の経験では、System.gc()を使用することは、事実上、プラットフォーム固有の最適化形式です(「プラットフォーム」とは、ハードウェアアーキテクチャ、OS、JVMバージョン、および利用可能なRAMなどの実行時パラメーターの組み合わせです)。特定のプラットフォームで大まかに予測可能ですが、プラットフォーム間で大幅に変動する可能性があります。

はい、そこにあるにSystem.gc()は(認知)のパフォーマンスが向上します状況は。たとえば、アプリの一部で遅延が許容できるが他の部分では許容できない場合(上記のゲームの例では、GCをレベルの開始時ではなくレベルの開始時に発生させたい場合)。

ただし、それが役立つか傷つくか(または何もしない)は、プラットフォーム(上記で定義)に大きく依存します。

したがって、これは最後の手段であるプラットフォーム固有の最適化として有効であると思います(つまり、他のパフォーマンス最適化では不十分な場合)。しかし、(特定のベンチマークなしで)それが役立つかもしれないと信じているからといって、それを呼び出すべきではありません。


0
  1. オブジェクトはnew演算子を使用して動的に割り当てられる ため
    、そのようなオブジェクトがどのように破棄され、それらの
    メモリが後で再割り当てするために解放されるのか疑問に思われるかもしれません。

  2. C ++などの一部の言語では、動的に割り当てられたオブジェクトは、削除演算子を使用して手動で解放する必要があります。

  3. Javaは異なるアプローチを取ります。自動的に割り当て解除を処理します。
  4. これを実現する手法は、ガベージコレクションと呼ばれます。これは次のように機能します。オブジェクトへの参照が存在しない場合、そのオブジェクトは不要であると見なされ、オブジェクトが占有していたメモリは解放されます。C ++のようにオブジェクトを破棄する明示的な必要はありません。
  5. ガベージコレクションは、プログラムの実行中に(もしあれば)散発的にのみ発生します。
  6. 使用されなくなったオブジェクトが1つ以上存在するという理由だけでは発生しません。
  7. さらに、Javaランタイムの実装が異なれば、ガベージコレクションへのアプローチも異なりますが、ほとんどの場合、プログラムの作成中にそのことを考慮する必要はありません。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.