たとえ難しい場合でも、Javaでガベージコレクションを強制することは可能ですか?私が知っているSystem.gc();
とRuntime.gc();
、彼らは唯一のGCを行うことを示唆しています。どのようにGCを強制できますか?
たとえ難しい場合でも、Javaでガベージコレクションを強制することは可能ですか?私が知っているSystem.gc();
とRuntime.gc();
、彼らは唯一のGCを行うことを示唆しています。どのようにGCを強制できますか?
回答:
あなたの最善のオプションはSystem.gc()
、ガベージコレクターがコレクションを実行するためのヒントであるを呼び出すことです。ガベージコレクターは非決定的であるため、強制的に即時に収集する方法はありません。
non-deterministic == trouble
GC.Collect()
は、.NET は収集しません。Java gc()
ではそうです。
jlibsライブラリは、ガベージコレクションのための優れたユーティリティクラスを持っています。WeakReferenceオブジェクトで気の利いた小さなトリックを使用して、ガベージコレクションを強制できます。
/**
* 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();
}
}
PhantomReference
with a を使用するReferenceQueue
ことです。ファイナライズ後、ただしクリーンアップの前に通知されます。最後に、このオブジェクトのメモリが解放されたことを検出できたとしても、HotSpotのような世代別GCではほとんど意味がありません。通常、それは若い世代の片付けと一致します。
System.gc(); System.gc();
、それがそれよりもうまく機能したかどうかを知ることは確かに興味深いでしょう。実際、何回コールしたかを印刷するだけSystem.gc()
で十分です。2に到達するチャンスは非常にわずかです。
使用したJava™仮想マシンツールインタフェース(JVM TI) 、機能を
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
「VMにガベージコレクションを強制的に実行させます。」JVM TIは、JavaTMプラットフォームデバッガアーキテクチャ(JPDA)の一部です。
はい、ほぼ同じ順序でメソッドを呼び出さなければならないことはほぼ可能ですが、これは次のとおりです。
System.gc ();
System.runFinalization ();
この2つのメソッドの使用を同時にクリーンアップするオブジェクトが1つしかない場合でも、ガベージコレクターfinalise()
は到達できないオブジェクトのメソッドを使用して、割り当てられたメモリを解放し、finalize()
メソッドが示すことを実行します。
ただし、ガベージコレクターを使用するとメモリに最悪の場合でもソフトウェアに過負荷がかかる可能性があるため、ガベージコレクターを使用するのはひどい習慣です。ガベージコレクターには独自のスレッドがあり、それに応じてプラスを制御できません。 gcが使用するアルゴリズムは時間がかかる可能性があり、非常に非効率的であると考えられます。ソフトウェアが確実に壊れているため、gcを使用して最悪の場合はソフトウェアをチェックする必要があります。優れたソリューションはgcに依存してはなりません。
注:これは、finalizeメソッドがオブジェクトの再割り当てでない場合にのみ機能することを覚えておいてください。これが発生した場合、オブジェクトは存続し、技術的に可能な復活があります。
gc()
ように、ガベージコレクションを実行するためのヒントにすぎません。runFinalizers()
「破棄されていることが判明した」オブジェクトに対してのみファイナライザを実行します。GCが実際に実行されなかった場合、そのようなオブジェクトは存在しない可能性があります...
OutOfMemoryErrorのドキュメントでは、フルガベージコレクションの後でVMがメモリの再利用に失敗しない限りスローされないことを宣言しています。したがって、エラーが発生するまでメモリを割り当て続けると、すでに完全なガベージコレクションが強制されています。
おそらくあなたが本当に聞きたかった質問は、「ガベージコレクションによって再利用する必要があると思うメモリをどのように再利用できるか」です。
(System.gc()からではなく)手動でGCを要求するには:
.gcは将来のリリースでの削除の候補です。Sunのエンジニアはかつて、世界中で20人未満の人が実際に.gc()の使用方法を知っているとコメントしていました-昨夜、セントラル/クリティカルでいくつかの作業を行いましたSecureRandomで生成されたデータを使用したデータ構造。40,000オブジェクトを少し超えたところで、VMはポインターが不足したかのようにスローダウンしました。明らかに、それは16ビットポインターテーブルをどんどん狭めていて、古典的な「機能しない機械」の動作を示しました。
私は-Xmsなどを試し、約57、xxxまで実行されるまで少しいじっていました。次に、gc()の後に、57,127から57,128までのgcを実行します-キャンプEasy Moneyでのコード膨張のペースで。
設計には基本的な再作業、おそらくスライディングウィンドウアプローチが必要です。
コマンドラインからGCをトリガーできます。これは、batch / crontabに役立ちます。
jdk1.7.0/bin/jcmd <pid> GC.run
見る :
JVM仕様は、ガベージコレクションについて何も特定していません。このため、ベンダーは自由にGCを実装できます。
したがって、このあいまいさがガベージコレクションの動作に不確実性をもたらします。ガベージコレクションのアプローチ/アルゴリズムについて知るには、JVMの詳細を確認する必要があります。また、動作をカスタマイズするオプションもあります。
ガベージコレクションが必要な理由を説明してください。あなたはSWTを使用している場合は、次のようなリソースを配置することができますImage
し、Font
メモリを解放します。例えば:
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
未処理のリソースを判別するためのツールもあります。
メモリを使い果たしてOutOfMemoryException
を取得している場合はjava -Xms128m -Xmx512m
、単にの代わりにを使用してプログラムを開始することにより、Javaが利用できるヒープスペースの量を増やすことができますjava
。これにより、128Mbの初期ヒープサイズと最大512Mbが得られます。これは、標準の32Mb / 128Mbをはるかに超えています。
java -Xms512M -Xmx1024M
別のオプションは、新しいオブジェクトを作成しないことです。
オブジェクトプーリングは、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) { }
}
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をクリーンアップできなくなります。
本当に、私はあなたを理解していません。しかし、「無限オブジェクトの作成」について明確にするために、私は大きなシステムにいくつかのコードがあり、それを処理してメモリ内に存在するオブジェクトの作成を行うことを意味しました。
これは正しい、唯一のジェスチャーです。あなたは、すでにいくつかのポスターによって与えられている標準的な答えをほとんど持っています。これを一つずつ見てみましょう:
正解です。実際のjvmはありません。これは仕様であり、望ましい動作を説明するコンピュータサイエンスの集まりです...私は最近、ネイティブコードからJavaオブジェクトを初期化することに取り組みました。必要なものを取得するための唯一の方法は、アグレッシブヌリングと呼ばれる方法を実行することです。間違った場合の間違いは非常に悪いので、質問の元の範囲に限定する必要があります。
オブジェクトの全体または一度に1つのアイテムを渡されているかどうかを確認する必要がある場合、ここでのポスターのほとんどは、インターフェイスに取り組んでいると言っていることを前提としています。
オブジェクトが不要になった場合は、オブジェクトにnullを割り当てることができますが、間違った場合はnullポインタ例外が生成されます。NIOを使えばもっといい仕事ができると思う
あなた、私、または他の誰かが取得したときはいつでも:「恐ろしくそれが必要です。」それはあなたが取り組んでいるもののほぼ完全な破壊のほぼ普遍的な前兆です...小さなサンプルコードを書いて、それからサニタイズしてください実際のコードが使用され、あなたの質問が表示されます。
イライラしないでください。多くの場合、これが解決するのは、dbaがどこかで購入したパッケージを使用していて、元のデザインが大規模なデータ構造に合わせて調整されていないことです。
それは非常に一般的です。
ご参考までに
メソッド呼び出しSystem.runFinalizersOnExit(true)は、Javaがシャットダウンする前にファイナライザメソッドが呼び出されることを保証します。ただし、この方法は本質的に安全ではなく、廃止されました。別の方法は、Runtime.addShutdownHookメソッドを使用して「シャットダウンフック」を追加することです。
マサラト・シディキ
ガベージコレクターを強制するいくつかの間接的な方法があります。ガベージコレクタが実行される時点まで、一時オブジェクトでヒープを埋めるだけです。私はこのようにガベージコレクターを強制するクラスを作りました:
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の移植方法かもしれないとき。
ここに何か付け加えたいと思います。Javaは仮想マシン上で実行され、実際のマシン上では実行されないことに注意してください。仮想マシンには、マシンとの独自の通信方法があります。システムによって異なる場合があります。次に、GCを呼び出すときに、Javaの仮想マシンにガベージコレクターを呼び出すように依頼します。
ガベージコレクターは仮想マシンに付属しているため、そこで強制的にクリーンアップを実行することはできません。むしろ、ガベージコレクターでリクエストをキューに入れます。これは仮想マシンに依存しますが、特定の時間が経過すると(これはシステム間で変化する可能性があります。通常、JVMに割り当てられたしきい値メモリがいっぱいになると)、実際のマシンがスペースを解放します。:D
次のコードは、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の例