このエラーは、それぞれ数個(15〜20個)のテキストエントリを持つ数十万個のHashMapオブジェクトを作成するプログラムで発生します。これらの文字列は、データベースに送信される前に(少量に分割することなく)すべて収集する必要があります。
Sunによれば、「ガベージコレクションに時間がかかり過ぎると、エラーが発生します。合計時間の98%以上がガベージコレクションに費やされ、2%未満のヒープしか回復されない場合、OutOfMemoryErrorがスローされます。 ".
明らかに、コマンドラインを使用してJVMに引数を渡すことができます。
最初のアプローチはうまくいき、2番目のアプローチは別のJava.lang.OutOfMemoryErrorになります。今回はヒープについてです。
だから、質問:特定のユースケース(すなわち、いくつかの小さなHashMapオブジェクト)のために、これに代わるプログラム的な代替策はありますか。たとえば、HashMapのclear()メソッドを使用すると、問題は解決しますが、HashMapに格納されているデータも同様です。 :-)
この問題はStackOverflowの 関連トピックでも議論されています。
プロセスを円滑に実行するために、基本的にメモリ不足になっています。頭に浮かぶオプション:
-Xmx512m
のように何かを試してくださいHashMap
オブジェクトをまとめて処理します。HashMap
に入れる前に String.intern()
を使用してください。HashMap(int initialCapacity, float loadFactor)
コンストラクタを使ってください次は私のために働いた。次のコードを追加するだけです。
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"
}
}
@takrl:このオプションのデフォルト設定は以下のとおりです。
Java -XX:+UseConcMarkSweepGC
つまり、このオプションはデフォルトではアクティブになっていません。それで、あなたがオプション "+XX:UseConcMarkSweepGC
"を使ったと言うとき、私はあなたがこの構文を使っていたと思います:
Java -XX:+UseConcMarkSweepGC
つまり、このオプションを明示的に有効にしていました。 Java HotSpot VM Options
の正しい構文とデフォルト設定について@ this document
記録のために、我々は今日同じ問題を抱えていた。このオプションを使用して修正しました。
-XX:-UseConcMarkSweepGC
どうやら、これはガベージコレクションのために使われた戦略を修正した、そしてそれは問題を消滅させた。
うーん...どちらかする必要があります:
アルゴリズムとデータ構造を完全に考え直すことで、これらすべての小さなHashMapが不要になるようにします。
必要に応じて、それらのHashMapをメモリーにページインおよびページアウトできるファサードを作成します。単純なLRUキャッシュは単なるチケットかもしれません。
JVMで使用可能なメモリーを使い果たします。もしあなたがこの獣をホストするマシンの管理をしているのであれば、必要であればもっとRAMを購入するのが最も速い、最も安い解決策かもしれません。とは言っても、私は一般的に、「より多くのハードウェアを投入する」ソリューションのファンではありません。あなたがこれらの問題のひとつひとつにもっと多くのハードウェアを投げ続けるなら、あなたはすぐに利益を減らすことの法則に出くわす。
とにかく何をしようとしていますか?実際の問題にはもっと良いアプローチがあると思います。
最後まで到達するのを待っている間、メモリ全体に構造体を格納しないでください。
ハッシュマップではなくデータベースの一時テーブルに中間結果を書き込む - 機能的には、データベーステーブルはハッシュマップに相当します。つまり、両方ともデータへのキーアクセスをサポートしますが、テーブルはメモリバインドされていません。ハッシュマップ.
正しく行われていれば、あなたのアルゴリズムは変更に気付くべきではありません - 正しくここではハッシュマップのようにそれにput(key、value)とget(key)メソッドを与えてもテーブルを表すクラスを使うことを意味します。
中間テーブルが完成したら、メモリからではなく、中間テーブルから必要なSQL文を生成します。
ガベージコレクションに時間がかかりすぎると、パラレルコレクターはOutOfMemoryError
をスローします。特に、合計時間の98%以上がガベージコレクションに費やされ、2%未満のヒープしか回復されない場合、OutOfMemoryError
がスローされます。この機能は、ヒープが小さすぎるために、ほとんどまたはまったく進まずに、アプリケーションが長時間実行されないようにするためのものです。必要に応じて、この機能はオプション-XX:-UseGCOverheadLimit
をコマンドラインに追加することで無効にできます。
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/ /
あなたが何十万ものハッシュマップを作成しているなら、あなたはおそらくあなたが実際に必要とするよりはるかに多くを使っています。大きなファイルやグラフィックを扱っているのでなければ、単純なデータを格納してもJavaのメモリ制限を超えることはありません。
あなたは自分のアルゴリズムを再考するべきです。この場合、私はその話題についてもっと助けを提供するでしょう、しかしあなたが問題の文脈についてもっと多くを提供するまで私は少しの情報も与えることができません。
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.lang.OutOfMemoryError:Java.lang.AbstractStringBuilderでGCオーバーヘッドの制限を超えました"
javaヒープスペースを2GB、つまり-Xmx2g.
に増やします。
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
このために、Androidクロージャの下にあるアプリGradleファイル内の以下のコードを使用してください。
dexOptions {javaMaxHeapSize "4g"}
私の場合は、-Xmx
オプションを使用してメモリを増やすことが解決策でした。
私は10gのファイルをJavaで読みとらせても同じエラーが出ました。これは、RES
コマンドのtop
列の値が-Xmxオプションで設定された値に達したときに起こりました。それから-Xmx
オプションを使ってメモリを増やすことですべてうまくいきました。
また別の点がありました。ユーザーアカウントでJava_OPTS
またはCATALINA_OPTS
を設定してメモリの量を増やしたときに、同じエラーが発生しました。それから、私は自分の設定したものとは異なる値を与えたそれらの環境変数の値を私のコードの中に表示しました。その理由は、Tomcatがそのプロセスのルートであり、それから私がsu-doerではなかったので、管理者にTomcatのcatalina.sh
のメモリを増やすように依頼したためです。
これは私がこのエラーを取り除くのを助けました。このオプションは-XXを無効にします:+ DisableExplicitGC