web-dev-qa-db-ja.com

java.lang.OutOfMemoryError:GCオーバーヘッド制限を超えました

このエラーは、それぞれ数個(15〜20個)のテキストエントリを持つ数十万個のHashMapオブジェクトを作成するプログラムで発生します。これらの文字列は、データベースに送信される前に(少量に分割することなく)すべて収集する必要があります。

Sunによれば、「ガベージコレクションに時間がかかり過ぎると、エラーが発生します。合計時間の98%以上がガベージコレクションに費やされ、2%未満のヒープしか回復されない場合、OutOfMemoryErrorがスローされます。 ".

明らかに、コマンドラインを使用してJVMに引数を渡すことができます。

  • "-Xmx1024m"(またはそれ以上)でヒープサイズを増やす、または
  • "-XX:-UseGCOverheadLimit"を使用して、エラーチェックを完全に無効にします。

最初のアプローチはうまくいき、2番目のアプローチは別のJava.lang.OutOfMemoryErrorになります。今回はヒープについてです。

だから、質問:特定のユースケース(すなわち、いくつかの小さなHashMapオブジェクト)のために、これに代わるプログラム的な代替策はありますか。たとえば、HashMapのclear()メソッドを使用すると、問題は解決しますが、HashMapに格納されているデータも同様です。 :-)

この問題はStackOverflowの 関連トピックでも議論されています。

316
PNS

プロセスを円滑に実行するために、基本的にメモリ不足になっています。頭に浮かぶオプション:

  1. あなたが言ったようにもっと多くのメモリを指定し、最初に-Xmx512mのように何かを試してください
  2. 可能であれば、小さなバッチのHashMapオブジェクトをまとめて処理します。
  3. 重複する文字列がたくさんある場合は、それらをHashMapに入れる前に String.intern() を使用してください。
  4. あなたのケースに合わせて HashMap(int initialCapacity, float loadFactor) コンストラクタを使ってください
157
WhiteFang34

次は私のために働いた。次のコードを追加するだけです。

dexOptions {
        javaMaxHeapSize "4g"
}

あなたのbuild.gradleに:

Android {
    compileSdkVersion 23
    buildToolsVersion '23.0.1'

    defaultConfig {
        applicationId "yourpackage"
        minSdkVersion 14
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"

        multiDexEnabled true
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-Android.txt'), 'proguard-rules.pro'
        }
    }

    packagingOptions {

    }

    dexOptions {
        javaMaxHeapSize "4g"
    }
}
60
Mina Fawzy

@takrl:このオプションのデフォルト設定は以下のとおりです。

Java -XX:+UseConcMarkSweepGC

つまり、このオプションはデフォルトではアクティブになっていません。それで、あなたがオプション "+XX:UseConcMarkSweepGC"を使ったと言うとき、私はあなたがこの構文を使っていたと思います:

Java -XX:+UseConcMarkSweepGC

つまり、このオプションを明示的に有効にしていました。 Java HotSpot VM Optionsの正しい構文とデフォルト設定について@ this document

42
qupera

記録のために、我々は今日同じ問題を抱えていた。このオプションを使用して修正しました。

-XX:-UseConcMarkSweepGC

どうやら、これはガベージコレクションのために使われた戦略を修正した、そしてそれは問題を消滅させた。

23
takrl

うーん...どちらかする必要があります:

  1. アルゴリズムとデータ構造を完全に考え直すことで、これらすべての小さなHashMapが不要になるようにします。

  2. 必要に応じて、それらのHashMapをメモリーにページインおよびページアウトできるファサードを作成します。単純なLRUキャッシュは単なるチケットかもしれません。

  3. JVMで使用可能なメモリーを使い果たします。もしあなたがこの獣をホストするマシンの管理をしているのであれば、必要であればもっとRAMを購入するのが最も速い、最も安い解決策かもしれません。とは言っても、私は一般的に、「より多くのハードウェアを投入する」ソリューションのファンではありません。あなたがこれらの問題のひとつひとつにもっと多くのハードウェアを投げ続けるなら、あなたはすぐに利益を減らすことの法則に出くわす。

とにかく何をしようとしていますか?実際の問題にはもっと良いアプローチがあると思います。

12
corlettk

最後まで到達するのを待っている間、メモリ全体に構造体を格納しないでください。

ハッシュマップではなくデータベースの一時テーブルに中間結果を書き込む - 機能的には、データベーステーブルはハッシュマップに相当します。つまり、両方ともデータへのキーアクセスをサポートしますが、テーブルはメモリバインドされていません。ハッシュマップ.

正しく行われていれば、あなたのアルゴリズムは変更に気付くべきではありません - 正しくここではハッシュマップのようにそれにput(key、value)とget(key)メソッドを与えてもテーブルを表すクラスを使うことを意味します。

中間テーブルが完成したら、メモリからではなく、中間テーブルから必要なSQL文を生成します。

9

代替のHashMap実装を使用してください( Trove )。標準のJava HashMapには、12倍以上のメモリオーバーヘッドがあります。詳細を読むことができます ここ

9
dir

ガベージコレクションに時間がかかりすぎると、パラレルコレクターはOutOfMemoryErrorをスローします。特に、合計時間の98%以上がガベージコレクションに費やされ、2%未満のヒープしか回復されない場合、OutOfMemoryErrorがスローされます。この機能は、ヒープが小さすぎるために、ほとんどまたはまったく進まずに、アプリケーションが長時間実行されないようにするためのものです。必要に応じて、この機能はオプション-XX:-UseGCOverheadLimitをコマンドラインに追加することで無効にできます。

8
user3405305

Java8 があり、 G1 Garbage Collector を使用できる場合は、次のようにアプリケーションを実行します。

 -XX:+UseG1GC -XX:+UseStringDeduplication

これはG1に似たような文字列を見つけてそれらの1つだけをメモリに保存するように伝えます、そして他のものはメモリ内のその文字列へのポインタです。

これは、繰り返し文字列がたくさんある場合に便利です。この解決策はうまくいくかもしれないし、働かないかもしれず、それぞれのアプリケーションに依存します。

詳細情報:
https://blog.codecentric.de/en/2014/08/string-deduplication-new-feature-Java-8-update-20-2/http:// Java -performance.info/Java-string-deduplication/ /

5
George C

あなたが何十万ものハッシュマップを作成しているなら、あなたはおそらくあなたが実際に必要とするよりはるかに多くを使っています。大きなファイルやグラフィックを扱っているのでなければ、単純なデータを格納してもJavaのメモリ制限を超えることはありません。

あなたは自分のアルゴリズムを再考するべきです。この場合、私はその話題についてもっと助けを提供するでしょう、しかしあなたが問題の文脈についてもっと多くを提供するまで私は少しの情報も与えることができません。

5
RétroX

Eclipse _ mat _ または VisualVM などのプロファイルツールを使用して、アプリケーションのメモリリークを修正します。

JDK 1.7.x以降のバージョンでは、G1GC他のGCアルゴリズムの2%とは異なり、ガベージコレクションに10%を費やす)を使用してください。

-Xms1g -Xmx2gでヒープメモリを設定することとは別に、 `を試してみてください

-XX:+UseG1GC 
-XX:G1HeapRegionSize=n, 
-XX:MaxGCPauseMillis=m, 
-XX:ParallelGCThreads=n, 
-XX:ConcGCThreads=n`

これらのパラメータの微調整については、 Oracle の記事をご覧ください。

SEのG1GCに関するいくつかの質問:

Java 7(JDK 7)のガベージコレクションとG1のドキュメント /

運用中のJava G1ガベージコレクション

積極的なガベージコレクタ戦略

3
Ravindra babu

エラーの場合:

"内部コンパイラエラー:Java.lang.OutOfMemoryError:Java.lang.AbstractStringBuilderでGCオーバーヘッドの制限を超えました"

javaヒープスペースを2GB、つまり-Xmx2g.に増やします。

2
bpb

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
)
and

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
2
shashi

このために、Androidクロージャの下にあるアプリGradleファイル内の以下のコードを使用してください。

dexOptions {javaMaxHeapSize "4g"}

2

私の場合は、-Xmxオプションを使用してメモリを増やすことが解決策でした。

私は10gのファイルをJavaで読みとらせても同じエラーが出ました。これは、RESコマンドのtop列の値が-Xmxオプションで設定された値に達したときに起こりました。それから-Xmxオプションを使ってメモリを増やすことですべてうまくいきました。

また別の点がありました。ユーザーアカウントでJava_OPTSまたはCATALINA_OPTSを設定してメモリの量を増やしたときに、同じエラーが発生しました。それから、私は自分の設定したものとは異なる値を与えたそれらの環境変数の値を私のコードの中に表示しました。その理由は、Tomcatがそのプロセスのルートであり、それから私がsu-doerではなかったので、管理者にTomcatのcatalina.shのメモリを増やすように依頼したためです。

1
M. Mashaye

これは私がこのエラーを取り除くのを助けました。このオプションは-XXを無効にします:+ DisableExplicitGC

0
kanaparthikiran