JUnitのテストを実行すると、このようなエラーメッセージが表示されます:
java.lang.OutOfMemoryError: GC overhead limit exceeded
OutOfMemoryError`はわかるが、GC overhead limitはどういう意味か?どうすればこれを解決できるのでしょうか?
このメッセージは、何らかの理由でガベージコレクタが過剰な時間(デフォルトではプロセスの全CPU時間の98%)をかけて、各実行で非常に少ないメモリ(デフォルトではヒープの2%)を回復していることを意味します。
これは事実上、あなたのプログラムが何の進歩もしなくなり、常にガベージコレクションの実行だけに忙殺されることを意味します。
アプリケーションが何もせずにCPU時間を消費するのを防ぐために、JVMはこのError
を投げ、問題を診断する機会を与えます。
私が見た中で、このようなことが起こるのは、あるコードが、すでに非常にメモリ制約のある環境で、大量の一時オブジェクトと大量の弱参照オブジェクトを作成しているような稀なケースです。
例えば、CPU時間の98%がGCに費やされ、ヒープが2%未満しか回収されなかった場合、GCはこの例外を投げます。
この機能は、ヒープが小さすぎるために、アプリケーションがほとんど進展しないまま長時間実行されることを防ぐために設計されています。
コマンドラインオプションでオフにすることができます。 XX:-UseGCOverheadLimit`を使用します。
詳細はこちら
EDIT: 私より速くタイプできる人がいるようだ :)
それは大抵の場合、コードに原因があります。以下は簡単な例です:
import java.util.*;
public class GarbageCollector {
public static void main(String... args) {
System.out.printf("Testing...%n");
List<Double> list = new ArrayList<Double>();
for (int outer = 0; outer < 10000; outer++) {
// list = new ArrayList<Double>(10000); // BAD
// list = new ArrayList<Double>(); // WORSE
list.clear(); // BETTER
for (int inner = 0; inner < 10000; inner++) {
list.add(Math.random());
}
if (outer % 1000 == 0) {
System.out.printf("Outer loop at %d%n", outer);
}
}
System.out.printf("Done.%n");
}
}
Windows7 32bitでjava 1.6.0_24-b07を使用しています。
java -Xloggc:gc.log ガーベッジコレクタ
次にgc.logを見ます。
もちろん、これはベストなテストでもベストな設計でもありませんが、このようなループを実装せざるを得ない状況に直面したとき、あるいは挙動がおかしい既存のコードに対処するとき、新しいオブジェクトを作る代わりに再利用することを選択すれば、ガベージコレクタが邪魔になる回数を減らすことができます...。
エラーの原因。
GCオーバーヘッドの制限を超えた」は、ガベージコレクターが常に稼働しており、Javaプログラムの進行が非常に遅いことを示しています。
ごみ収集後。, Javaプロセスがガベージコレクションに費やす時間の約98%以上であり、ヒープの2%未満しか回復しておらず、これまでに過去5回を行っている場合。 (時間定数をコンパイルします。) 連続ゴミ収集。, 次に、 java.lang.OutOfMemoryError がスローされます。
1。 現在のヒープで不十分な場合は、ヒープサイズを増やします。
2。 ヒープメモリを増やしてもこのエラーが発生する場合は、MAT(メモリアナライザーツール)、Visual VMなどのメモリプロファイリングツールを使用して、メモリリークを修正します。
3。 JDKバージョンを最新バージョン(1.8.x)または少なくとも1.7.xにアップグレードし、G1GCアルゴリズムを使用します。 . G1 GCのスループット目標は、90%の適用時間と10%のガベージ収集時間です。
4。 -Xms1g -Xmx2g
でヒープメモリを設定する以外に、試してください。
-XX:+ UseG1GC -XX:G1HeapRegionSize = n -XX:MaxGCPauseMillis = m。
-XX:ParallelGCThreads = n -XX:ConcGCThreads = n。
G1GCに関するいくつかの関連する質問をご覧ください。
私にとって、次の手順は機能しました。
1。 eclipse.ini
ファイルを開きます。
2。 変化する。
<。!-言語:lang-none -->。
-Xms40m。
-Xmx512m。
に。
<。!-言語:lang-none -->。
-Xms512m。
-Xmx1024m。
3。 Eclipseを再起動します。
以下は私にとってはうまくいきました。 次のスニペットを追加するだけです。
android {
compileSdkVersion 25
buildToolsVersion '25.0.1'
defaultConfig {
applicationId "yourpackage"
minSdkVersion 10
targetSdkVersion 25
versionCode 1
versionName "1.0"
multiDexEnabled true
}
dexOptions {
javaMaxHeapSize "4g"
}
}
Javaヒープサイズの説明(xms、xmx、xmn)。
-Xms size in bytes
Example : java -Xms32m
Javaヒープの初期サイズを設定します。 デフォルトサイズは2097152(2MB)です。 値は、1024バイト(1KB)の倍数以上でなければなりません。 (-serverフラグにより、デフォルトサイズが32Mに増加します。)。
-Xmn size in bytes
Example : java -Xmx2m
Eden世代の初期Javaヒープサイズを設定します。 デフォルト値は640Kです。 (-serverフラグにより、デフォルトサイズが2Mに増加します。)
-Xmx size in bytes
Example : java -Xmx2048m
Javaヒープが成長できる最大サイズを設定します。 デフォルトサイズは64Mです。 (-serverフラグにより、デフォルトサイズが128Mに増加します。)。 最大ヒープ制限は約2 GB(2048MB)です。
Javaメモリ引数(xms、xmx、xmn)フォーマット。
Javaヒープサイズを設定するときは、MBの場合は「m」または「M」、GBの場合は「g」または「G」のいずれかの文字を使用してメモリ引数を指定する必要があります。 「MB」または「GB」を指定すると、設定は機能しません。有効な引数は次のようになります。
-Xms64mまたは-Xms64M。 -Xmx1gまたは-Xmx1G。 2048MBを使用して2GBを指定することもできます。 また、引数を指定するときは、整数だけを使用してください。 -Xmx512mの使用は有効なオプションですが、-Xmx0.5gはエラーを引き起こします。
この参照は誰かに役立ちます。
私はAndroid Studioで働いていて、リリース用に署名されたAPKを生成しようとしたときにこのエラーに遭遇しました。 デバッグAPKを問題なくビルドしてテストすることができましたが、リリースAPKを構築したいとすぐに、ビルドプロセスは数分間実行され、最後に「エラーjava.lang.OutOfMemoryError: GCオーバーヘッド制限を超えました。」. VMとAndroid DEXコンパイラの両方でヒープサイズを増やしましたが、問題は解決しませんでした。 最後に、何時間もコーヒーのマグカップの後で、問題が私のアプリレベルの「build.gradle」ファイルにあることが判明しました-リリースビルドタイプの「minifyEnabled」パラメーターを「false」に設定し、その結果Proguardを実行しましたコード縮小プロセスを経ていないコードのもの(https://developer.android.com/studio/build/shrinkを参照). 'minifyEnabled'パラメータを 'true'に変更し、リリースビルドを夢のように実行しました:)。
つまり、アプリレベルの「build.gradle」ファイルを次のファイルから変更する必要がありました。 //。..
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.sign_config_release
}
debug {
debuggable true
signingConfig signingConfigs.sign_config_debug
}
}
//...
に。
//...
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.sign_config_release
}
debug {
debuggable true
signingConfig signingConfigs.sign_config_debug
}
}
//...
Jdeveloperでメモリサイズを大きくする必要があります setDomainEnv.cmd に移動します。
set WLS_HOME=%WL_HOME%\server
set XMS_SUN_64BIT=**256**
set XMS_SUN_32BIT=**256**
set XMX_SUN_64BIT=**3072**
set XMX_SUN_32BIT=**3072**
set XMS_JROCKIT_64BIT=**256**
set XMS_JROCKIT_32BIT=**256**
set XMX_JROCKIT_64BIT=**1024**
set XMX_JROCKIT_32BIT=**1024**
if "%JAVA_VENDOR%"=="Sun" (
set WLS_MEM_ARGS_64BIT=**-Xms256m -Xmx512m**
set WLS_MEM_ARGS_32BIT=**-Xms256m -Xmx512m**
) else (
set WLS_MEM_ARGS_64BIT=**-Xms512m -Xmx512m**
set WLS_MEM_ARGS_32BIT=**-Xms512m -Xmx512m**
)
と。
set MEM_PERM_SIZE_64BIT=-XX:PermSize=**256m**
set MEM_PERM_SIZE_32BIT=-XX:PermSize=**256m**
if "%JAVA_USE_64BIT%"=="true" (
set MEM_PERM_SIZE=%MEM_PERM_SIZE_64BIT%
) else (
set MEM_PERM_SIZE=%MEM_PERM_SIZE_32BIT%
)
set MEM_MAX_PERM_SIZE_64BIT=-XX:MaxPermSize=**1024m**
set MEM_MAX_PERM_SIZE_32BIT=-XX:MaxPermSize=**1024m**