Javaでガベージコレクションを強制する方法は?


225

たとえ難しい場合でも、Javaでガベージコレクションを強制することは可能ですか?私が知っているSystem.gc();Runtime.gc();、彼らは唯一のGCを行うことを示唆しています。どのようにGCを強制できますか?


30
おそらく、GCを強制する必要がある理由の背景を提供すると役立つでしょう。通常、ガベージコレクションされた言語では、明示的にコレクターを呼び出すことはお勧めできません。
ジャスティンエティエ

3
特定のJVMにはいくつかのガベージコレクションメソッドがあり、それぞれに独自の利点と欠点があります。多くの場合、起動時にJVMにヒントを与えるだけで特定の状況を回避できます。シナリオについて詳しく説明してください。
するThorbjörnRavnアンデルセン

3
jmapの-histo:ライブ<PID> stackoverflow.com/questions/6418089/...

5
ガベージコレクションを強制するための使用例を次に示します。私は30 GBのヒープを備えたサーバーを使用しています。サーバーは5分ごとに約1分の時間を費やして、約35Mの追加オブジェクトが使用される複雑なタスクを実行します。フルGCは、常に複雑なタスク中に1時間に数回トリガーされ、VMを10〜15秒間フリーズします。複雑なタスクが実行されていないときに、フルGCを強制的に実行したいです。その場合、40Mではなく5Mのライブオブジェクトをジャグリングします。
Steve

3
@JustinEthier GCを強制したい場合が1つあります。これは、java.lang.ref.Reference型の階層に関連する動作の単体テストです。
エリアスヴァシレンコ2016年

回答:


168

あなたの最善のオプションはSystem.gc()、ガベージコレクターがコレクションを実行するためのヒントであるを呼び出すことです。ガベージコレクターは非決定的であるため、強制的に即時に収集する方法はありません。


28
あるはずです。non-deterministic == trouble
Pacerier 2014

7
ガベージコレクターは非決定的であり、即時のコレクションを強制する方法を提供する場合があります。たとえば、通常、.NETコレクターは非決定的ですが、GC.Collect()を呼び出すと強制的に実行されます。Javaがこの関数を公開しないことを選択しただけです。
PetrHudeček15年

2
私の経験では、このメソッドは常にガベージコレクターを呼び出します。それは十分な規則性をもって行われ、宣言されたオブジェクトの数に対するメモリ使用量のプロットは常に厳密に線形になります(パディングなどの説明)。
ジムピバルスキ

新しいオブジェクトを割り当て、その後それらを参照しないことにより、ガベージコレクターは自動的に実行されると考えていました
Bionix1441

@PetrHudeček実際のアプリケーションでGC.Collect()は、.NET は収集しません。Java gc()ではそうです。
ajeh 2018年

53

jlibsライブラリは、ガベージコレクションのための優れたユーティリティクラスを持っていますWeakReferenceオブジェクトで気の利いた小さなトリックを使用して、ガベージコレクションを強制できます。

jlibのRuntimeUtil.gc()

   /**
    * This method guarantees that garbage collection is
    * done unlike <code>{@link System#gc()}</code>
    */
   public static void gc() {
     Object obj = new Object();
     WeakReference ref = new WeakReference<Object>(obj);
     obj = null;
     while(ref.get() != null) {
       System.gc();
     }
   }

1
このコードは、参照が弱く到達可能になるとすぐに、つまりメモリから消去される前に、弱い参照が消去されるため、壊れています。
Marko Topolnik

1
「GCが実行されました」の意味を「メモリが解放されました」と混同している可能性があります。オブジェクトは存続し、まだファイナライズされていませんが、弱参照を介してアクセスすることはできません。やや良い方法は、PhantomReferencewith a を使用するReferenceQueueことです。ファイナライズ後、ただしクリーンアップの前に通知されます。最後に、このオブジェクトのメモリが解放されたことを検出できたとしても、HotSpotのような世代別GCではほとんど意味がありません。通常、それは若い世代の片付けと一致します。
Marko Topolnik

20
OPは、「ガベージコレクションを強制する」ためのソリューションを要求し、提供すると主張しました。GCサブシステムの実行は1つのことであり、実際にはゴミを収集することです。あなたが提供したコードサンプルは明らかにゴミが収集されたことを保証する意図を持っています。とにかく、これは非常に古い質問なので、OPの希望ではなく、一般の人々にとっての有用性についてです。「GCサブシステムを強制的に実行する」ことに誰も関心がなく、ガベージは収集されていません。実際、人々は通常、すべてのゴミが収集されたことの保証を求めています。
Marko Topolnik、2012

4
あなたはおそらくそれをの効率と比較しなかったでしょうがSystem.gc(); System.gc();、それがそれよりもうまく機能したかどうかを知ることは確かに興味深いでしょう。実際、何回コールしたかを印刷するだけSystem.gc()で十分です。2に到達するチャンスは非常にわずかです。
Marko Topolnik

3
@MarkoTopolnik:「ガベージが収集されずに、「GCサブシステムを強制的に実行する」ことに誰も関心がない」...実際、今日私はこの動作だけに関心がありました。この回答があったことに感謝します。私の目的は、GCログ処理の回転動作を確認し、GC出力の形式を取得することでした。この小さなトリックは、GCログをすぐにいっぱいにするのに役立ちました。
erik.weathers 2017年

49

GCを強制するための最良の方法(それだけではないにしても)は、カスタムJVMを作成することです。ガベージコレクターはプラグイン可能であるため、おそらく使用可能な実装の1つを選択して微調整することができます。

注:これは簡単な答えではありません。


40
lulzの+1。ユーモアのセンスがある人よりもイライラするデバッグの方が優れているものはありません。実際に使用可能な答え以外、つまりです。
jsh 2012年


25

はい、ほぼ同じ順序でメソッドを呼び出さなければならないことはほぼ可能ですが、これは次のとおりです。

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

この2つのメソッドの使用を同時にクリーンアップするオブジェクトが1つしかない場合でも、ガベージコレクターfinalise()は到達できないオブジェクトのメソッドを使用して、割り当てられたメモリを解放し、finalize()メソッドが示すことを実行します。

ただし、ガベージコレクターを使用するとメモリに最悪の場合でもソフトウェアに過負荷がかかる可能性があるため、ガベージコレクターを使用するのはひどい習慣です。ガベージコレクターには独自のスレッドがあり、それに応じてプラスを制御できません。 gcが使用するアルゴリズムは時間がかかる可能性があり、非常に非効率的であると考えられます。ソフトウェアが確実に壊れているため、gcを使用して最悪の場合はソフトウェアをチェックする必要があります。優れたソリューションはgcに依存してはなりません。

注:これは、finalizeメソッドがオブジェクトの再割り当てでない場合にのみ機能することを覚えておいてください。これが発生した場合、オブジェクトは存続し、技術的に可能な復活があります。


10
いいえ、これら2つのコマンドを実行しても、ガベージコレクションは強制されません。他の人がすでに述べたgc()ように、ガベージコレクションを実行するためのヒントにすぎません。runFinalizers()「破棄されていることが判明した」オブジェクトに対してのみファイナライザを実行します。GCが実際に実行されなかった場合、そのようなオブジェクトは存在しない可能性があります...
Steffen Heil

また、System.runFinalization()は、何かが実行されることを保証するものではありません。何も起こらない可能性があります。これは提案です – Javadocから:「このメソッドを呼び出すと、Java Virtual Machineが破棄が確認されたが、finalizeメソッドがまだ実行されていないオブジェクトのfinalizeメソッドの実行に労力を費やしていることを示しています
kaan

21

OutOfMemoryErrorのドキュメントでは、フルガベージコレクションの後でVMがメモリの再利用に失敗しない限りスローされないことを宣言しています。したがって、エラーが発生するまでメモリを割り当て続けると、すでに完全なガベージコレクションが強制されています。

おそらくあなたが本当に聞きたかった質問は、「ガベージコレクションによって再利用する必要があると思うメモリをどのように再利用できるか」です。


18

(System.gc()からではなく)手動でGCを要求するには:

  1. 移動先:JDKのbinフォルダー(例:-C:\ Program Files \ Java \ jdk1.6.0_31 \ bin)
  2. jconsole.exeを開きます
  3. 目的のローカルプロセスに接続します。
  4. [メモリ]タブに移動し、[GCの実行]をクリックします。

3
誤解を招く可能性があります。[Perform GC]ボタンをマウスでポイントしてください。JVMにGCの実行を要求できますが、強制することはできません。
Kumaran

@PinkeshSharma、これは強制しません。これは単なる要求であり、おそらく完全に無視されます。
Pacerier 2014

@Pacerier理想的な世界ではそうですが、これを行うと、メモリが即座に増加することが
わかり

11

.gcは将来のリリースでの削除の候補です。Sunのエンジニアはかつて、世界中で20人未満の人が実際に.gc()の使用方法を知っているとコメントしていました-昨夜、セントラル/クリティカルでいくつかの作業を行いましたSecureRandomで生成されたデータを使用したデータ構造。40,000オブジェクトを少し超えたところで、VMはポインターが不足したかのようにスローダウンしました。明らかに、それは16ビットポインターテーブルをどんどん狭めていて、古典的な「機能しない機械」の動作を示しました。

私は-Xmsなどを試し、約57、xxxまで実行されるまで少しいじっていました。次に、gc()の後に、57,127から57,128までのgcを実行します-キャンプEasy Moneyでのコード膨張のペースで。

設計には基本的な再作業、おそらくスライディングウィンドウアプローチが必要です。


1
私はそのようなものを持っています、メモリ内の多くのオブジェクトはそれらの割り当てを解除できません。OutOfMemory例外がスローされます。無限オブジェクトの作成プロセスがあるかどうか、またはこれらのオブジェクトがシステムで使用されているものであるかどうかをGCに強制的にテストさせたいです。

あなたは私と同じ問題に取り組んでいるように聞こえます、plsは説明します:「無限オブジェクトの作成」...良い研究プロジェクト、多分あなたはここのJava領域に質問や何かを投稿することができますサイトがどのように機能するかについての「Finite Automa」を知っています)コンパイラが40,000のbase36 BigIntegersで「コードが多すぎる」と文句を言ったため、昨日試してfile.datを実行しました。ここでは、JVM全体が16ビットポインターに制限されていると推測しています。私たちがしなければならないことは、積極的にnullにしてディスクから読み取ることです...
Nicholas Jordan

本当に、私はあなたを理解していません。しかし、「無限オブジェクトの作成」について明確にするために、私は私の大きなシステムに、メモリ内で処理して生きているオブジェクトの作成を行うコードがあることを意味しました。このコードを実際には取得できませんでした。ジェスチャーだけです!!

5
ナンセンス!これを使用する必要がある明らかなケースが1つあります。弱参照を使用するコードをテストして、弱参照が解消されたときに動作が正しいことを確認できるようにするためです。
エリアスヴァシレンコ


6

JVM仕様は、ガベージコレクションについて何も特定していません。このため、ベンダーは自由にGCを実装できます。

したがって、このあいまいさがガベージコレクションの動作に不確実性をもたらします。ガベージコレクションのアプローチ/アルゴリズムについて知るには、JVMの詳細を確認する必要があります。また、動作をカスタマイズするオプションもあります。


4

ガベージコレクションを強制する必要がある場合は、リソースの管理方法を検討する必要があります。メモリ内に永続する大きなオブジェクトを作成していますか?Disposableインターフェースを備えた大きなオブジェクト(グラフィッククラスなど)を作成していて、それを使用しても呼び出さないのdispose()ですか?単一のメソッド内でのみ必要なクラスレベルで何かを宣言していますか?


2

ガベージコレクションが必要な理由を説明してください。あなたはSWTを使用している場合は、次のようなリソースを配置することができますImageし、Fontメモリを解放します。例えば:

Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();

未処理のリソースを判別するためのツールもあります。


破棄メソッドがない場合はどうなりますか?
ArifMustafa

1
質問とはまったく無関係です!いいえ、SWTは使用していません。Delphiネイティブレイヤーを介して.NETウィンドウを開くJNIメソッドを呼び出しています。また、ネイティブC ++レイヤーを介してデータを受信するFORTRAN計算コアもあります。それは何と関係がありますか?GCを強制することはできますか?番号?:-(
モスタファZeinali 2018

0

メモリを使い果たしてOutOfMemoryExceptionを取得している場合はjava -Xms128m -Xmx512m、単にの代わりにを使用してプログラムを開始することにより、Javaが利用できるヒープスペースの量を増やすことができますjava。これにより、128Mbの初期ヒープサイズと最大512Mbが得られます。これは、標準の32Mb / 128Mbをはるかに超えています。


デフォルトのメモリ設定は次のとおりですjava -Xms512M -Xmx1024M
ThePyroEagle

0

別のオプションは、新しいオブジェクトを作成しないことです。

オブジェクトプーリングは、JavaでのGCの必要性を減らすために廃止されました。

通常、オブジェクトのプールはオブジェクトの作成(軽量オブジェクトの場合はesp)よりも高速ではありませんが、ガベージコレクションよりは高速です。10,000個のオブジェクトを作成し、各オブジェクトが16バイトである場合。これは、GCが再利用する必要のある160,000バイトです。一方、10,000をすべて同時に必要としない場合は、プールを作成してオブジェクトをリサイクル/再利用できます。これにより、新しいオブジェクトを作成する必要がなくなり、古いオブジェクトをGCする必要がなくなります。

このようなもの(テストされていません)。また、スレッドセーフにする場合は、LinkedListをConcurrentLinkedQueueに交換できます。

public abstract class Pool<T> {
    private int mApproximateSize;
    private LinkedList<T> mPool = new LinkedList<>();

    public Pool(int approximateSize) {
        mApproximateSize = approximateSize;
    }

    public T attain() {
        T item = mPool.poll();
        if (item == null) {
            item = newInstance();
        }
        return item;
    }

    public void release(T item) {
        int approxSize = mPool.size(); // not guaranteed accurate
        if (approxSize < mApproximateSize) {
            recycle(item);
            mPool.add(item);
        } else if (approxSize > mApproximateSize) {
            decommission(mPool.poll());
        }
    }

    public abstract T newInstance();

    public abstract void recycle(T item);

    public void decommission(T item) { }

}

0

OracleJDK 10とG1 GCでは、1回の呼び出しでSystem.gc()GCが古いコレクションをクリーンアップします。GCがすぐに実行されるかどうかはわかりません。ただし、System.gc()ループで何度も呼び出されても、GCはYoung Collectionをクリーンアップしません。GCでYoung Collectionをクリーンアップするには、new byte[1024]を呼び出さずにループ(例:)で割り当てる必要がありますSystem.gc()System.gc()何らかの理由で呼び出すと、GCがYoung Collectionをクリーンアップできなくなります。


0

本当に、私はあなたを理解していません。しかし、「無限オブジェクトの作成」について明確にするために、私は大きなシステムにいくつかのコードがあり、それを処理してメモリ内に存在するオブジェクトの作成を行うことを意味しました。

これは正しい、唯一のジェスチャーです。あなたは、すでにいくつかのポスターによって与えられている標準的な答えをほとんど持っています。これを一つずつ見てみましょう:

  1. このコードを実際に取得できませんでした

正解です。実際のjvmはありません。これは仕様であり、望ましい動作を説明するコンピュータサイエンスの集まりです...私は最近、ネイティブコードからJavaオブジェクトを初期化することに取り組みました。必要なものを取得するための唯一の方法は、アグレッシブヌリングと呼ばれる方法を実行することです。間違った場合の間違いは非常に悪いので、質問の元の範囲に限定する必要があります。

  1. 私の大きなシステムのコードの一部はオブジェクトの作成を行います

オブジェクトの全体または一度に1つのアイテムを渡されているかどうかを確認する必要がある場合、ここでのポスターのほとんどは、インターフェイスに取り組んでいると言っていることを前提としています。

オブジェクトが不要になった場合は、オブジェクトにnullを割り当てることができますが、間違った場合はnullポインタ例外が生成されます。NIOを使えばもっといい仕事ができると思う

あなた、私、または他の誰かが取得したときはいつでも:「恐ろしくそれが必要です。」それはあなたが取り組んでいるもののほぼ完全な破壊のほぼ普遍的な前兆です...小さなサンプルコードを書いて、それからサニタイズしてください実際のコードが使用され、あなたの質問が表示されます。

イライラしないでください。多くの場合、これが解決するのは、dbaがどこかで購入したパッケージを使用していて、元のデザインが大規模なデータ構造に合わせて調整されていないことです。

それは非常に一般的です。


-1

ご参考までに

メソッド呼び出しSystem.runFinalizersOnExit(true)は、Javaがシャットダウンする前にファイナライザメソッドが呼び出されることを保証します。ただし、この方法は本質的に安全ではなく、廃止されました。別の方法は、Runtime.addShutdownHookメソッドを使用して「シャットダウンフック」を追加することです。

マサラト・シディキ


シャットダウンフックの欠点は、実際にはほとんど機能しないことです。強制終了は機能せず、ゼロ以外の終了コードは機能しません。また、(公式の)JVMは、実行する必要がある限り、それらを実行しない場合があります。
ThePyroEagle

-1

ガベージコレクターを強制するいくつかの間接的な方法があります。ガベージコレクタが実行される時点まで、一時オブジェクトでヒープを埋めるだけです。私はこのようにガベージコレクターを強制するクラスを作りました:

class GarbageCollectorManager {

    private static boolean collectionWasForced;
    private static int refCounter = 0;

    public GarbageCollectorManager() {
        refCounter++;
    }

    @Override
    protected void finalize() {
        try {
            collectionWasForced = true;
            refCounter--;
            super.finalize();   
        } catch (Throwable ex) {
            Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public int forceGarbageCollection() {
        final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
        int iterationsUntilCollected = 0;
        collectionWasForced = false;

        if (refCounter < 2) 
            new GarbageCollectorManager();

        while (!collectionWasForced) {
            iterationsUntilCollected++;
            int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
            arr = null;
        }

        return iterationsUntilCollected;
    }

}

使用法:

GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();

私はそれが常にヒープを満たすため、この方法は、便利であるどのくらいかわからないが、あなたは、ミッションクリティカルなアプリケーションがある場合はしなければならない GCを強制する-これは、GCを強制的にJavaの移植方法かもしれないとき。


「final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;」とは何ですか?
Koray Tugay

配列サイズ-GCが動作を開始するために生成される一時オブジェクト(int)の数。
Agnius Vasiliauskas

これは有効ですか:「_」は整数ですか?
Koray Tugay

1
はい。JavaSE 7以降、数値リテラルのアンダースコアは有効です。これは、この例のように、整数の桁区切り記号などに役立ちます。
Agnius Vasiliauskas

3
このようなコードを本番システムで実行しないでください。1つのスレッドでこのコードを実行、他のスレッドが....また、OutOfMemoryException例外を取得し、完全に最初の場所でこれを呼び出すの意思をの復帰かもしれないが
ステファン・ハイル

-1

ここに何か付け加えたいと思います。Javaは仮想マシン上で実行され、実際のマシン上では実行されないことに注意してください。仮想マシンには、マシンとの独自の通信方法があります。システムによって異なる場合があります。次に、GCを呼び出すときに、Javaの仮想マシンにガベージコレクターを呼び出すように依頼します。

ガベージコレクターは仮想マシンに付属しているため、そこで強制的にクリーンアップを実行することはできません。むしろ、ガベージコレクターでリクエストをキューに入れます。これは仮想マシンに依存しますが、特定の時間が経過すると(これはシステム間で変化する可能性があります。通常、JVMに割り当てられたしきい値メモリがいっぱいになると)、実際のマシンがスペースを解放します。:D


2番目の段落の最初の文は不等分割です。
ローン侯爵

-1

次のコードは、assertGC(...)メソッドから取得されます。非決定的なガベージコレクターに強制的に収集を試みます。

   List<byte[]> alloc = new ArrayList<byte[]>();
   int size = 100000;
   for (int i = 0; i < 50; i++) {
        if (ref.get() == null) {
             // Test succeeded! Week referenced object has been cleared by gc.
             return;
        }
        try {
             System.gc();
        } catch (OutOfMemoryError error) {
             // OK
        }
        try {
             System.runFinalization();
        } catch (OutOfMemoryError error) {
             // OK
        }

        // Approach the jvm maximal allocatable memory threshold
        try {
             // Allocates memory.
             alloc.add(new byte[size]);

             // The amount of allocated memory is increased for the next iteration.
             size = (int)(((double)size) * 1.3);
        } catch (OutOfMemoryError error) {
             // The amount of allocated memory is decreased for the next iteration.
             size = size / 2;
        }

        try {
             if (i % 3 == 0) Thread.sleep(321);
        } catch (InterruptedException t) {
             // ignore
        }
   }

   // Test failed! 

   // Free resources required for testing
   alloc = null;

   // Try to find out who holds the reference.
   String str = null;
   try {
        str = findRefsFromRoot(ref.get(), rootsHint);
   } catch (Exception e) {
        throw new AssertionFailedErrorException(e);
   } catch (OutOfMemoryError err) {
        // OK
   }
   fail(text + ":\n" + str);

ソース(明確にするためにコメントをいくつか追加しました):NbTestCaseの例


-1

Runtime.getRuntime().gc()ユーティリティメソッドを使用または使用することができますSystem.gc()注:これらのメソッドはGCを保証しません。また、その範囲は、アプリケーションでプログラム的に処理するのではなく、JVMに限定する必要があります。


2
他の回答で説明されているように、これらのメソッドは(完全な)ガベージコレクションの実行を強制しません。
Flow

-2

JUnitとSpringを使用している場合は、これをすべてのテストクラスに追加してみてください。

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