「java.lang.OutOfMemoryError」の対処方法:Java ヒープ スペース」エラー?
-
09-06-2019 - |
質問
クライアントサイドを書いています スイング アプリケーション (グラフィカル フォント デザイナー) Java 5. 。最近、遭遇するのは、 java.lang.OutOfMemoryError: Java heap space
メモリ使用量を控えめにしていないため、エラーが発生しました。ユーザーは無制限の数のファイルを開くことができ、プログラムは開かれたオブジェクトをメモリ内に保持します。簡単な調査の後、私は見つけました 5.0 Java 仮想マシンの人間工学 他の人は、Windows マシンでは JVM のデフォルトの最大ヒープ サイズが次のように設定されていると言っています。 64MB
.
この状況を考えると、この制約にどのように対処すればよいでしょうか?
増やすことができました 最大ヒープサイズ を使用して コマンドライン Java のオプションを使用できますが、使用可能な RAM を把握し、起動プログラムまたはスクリプトを作成する必要があります。さらに、いくつかに増加 有限の マックスはそうではありません 結局のところ 問題を取り除きます。
メモリを解放するために、コードの一部を書き換えてオブジェクトをファイル システムに頻繁に永続化することができます (データベースの使用も同じことです)。うまくいくかもしれないが、おそらく大変な作業でもあるだろう。
上記のアイデアの詳細や、次のような代替案を教えていただければ、 自動仮想メモリ、ヒープ サイズを動的に拡張, 、 それは素晴らしい。
解決
最終的には、実行しているプラットフォームに関係なく、使用できるヒープの最大値には常に限界があります。Windows 32 ビットではこれくらいです 2GB
(特にヒープではなく、プロセスごとのメモリの合計量)。たまたま、Java がデフォルトを小さくすることを選択しているだけです (おそらく、プログラマがこの問題に遭遇し、何をしているのかを正確に調べる必要なしに、暴走したメモリ割り当てを持つプログラムを作成できないようにするためです)。
したがって、必要なメモリの量を決定するか、使用しているメモリの量を減らすために実行できるアプローチがいくつかあることを考慮します。Java や C# などのガベージ コレクション言語でよくある間違いの 1 つは、オブジェクトへの参照を保持しておくことです。 もはや 可能な場合は多くのオブジェクトを使用または割り当てている 再利用 代わりに彼らを。オブジェクトに参照がある限り、ガベージ コレクターはオブジェクトを削除しないため、オブジェクトはヒープ領域を使用し続けます。
この場合、Java メモリ プロファイラを使用して、プログラム内のどのメソッドが大量のオブジェクトを割り当てているかを特定し、それらのメソッドが参照されないようにする方法、または最初からオブジェクトを割り当てないようにする方法があるかどうかを判断できます。私が過去に使用したオプションの 1 つは「JMP」です。 http://www.khelekore.org/jmp/.
これらのオブジェクトを何らかの理由で割り当てており、参照を維持する必要があると判断した場合 (実行内容によっては、これが当てはまる場合があります)、プログラムの開始時に最大ヒープ サイズを増やすだけで済みます。ただし、メモリ プロファイリングを実行し、オブジェクトがどのように割り当てられているかを理解すると、必要なメモリの量についてより適切なアイデアが得られるはずです。
一般に、プログラムが有限量のメモリ (おそらく入力サイズに応じて) で実行されることが保証できない場合、常にこの問題に遭遇します。これらをすべて実行した後でのみ、オブジェクトをディスクにキャッシュするなどの検討が必要になります。この時点で、何かのために「Xgb のメモリが必要だ」と言うのには十分な理由があるはずですが、アルゴリズムやメモリ割り当てパターンを改善してもそれを回避することはできません。一般に、これは大規模なデータセット (データベースや科学分析プログラムなど) で動作するアルゴリズムにのみ当てはまり、その場合には、キャッシュやメモリ マップド IO などの技術が役立ちます。
他のヒント
コマンドライン オプションを使用して Java を実行する -Xmx
, を設定します。 最大 ヒープのサイズ。
指定できます あたり プロジェクトに必要なヒープ領域の量を予測する
以下は、 エクリプス ヘリオス/ジュノー/ケプラー:
マウスを右クリックして
Run As - Run Configuration - Arguments - Vm Arguments,
それからこれを追加します
-Xmx2048m
ヒープ サイズの増加は「修正」ではなく、100% 一時的な「しっくい」です。またどこかでクラッシュするでしょう。これらの問題を回避するには、高パフォーマンスのコードを作成します。
- 可能な限りローカル変数を使用してください。
- 正しいオブジェクトを選択していることを確認してください (例:String、StringBuffer、StringBuilder の間の選択)
- プログラムに適切なコード システムを使用してください(例:静的変数と非静的変数の使用)
- コードで機能する可能性のあるその他のもの。
- マルチスレッドで動かしてみます
大きな注意点 ---- 私のオフィスでは、(一部の Windows マシンでは) Java ヒープに 512m を超える領域を割り当てることができないことがわかりました。これは、一部のマシンにインストールされている Kaspersky ウイルス対策製品が原因であることが判明しました。その AV 製品をアンインストールした後、少なくとも 1.6GB を割り当てることができることがわかりました。 -Xmx1600m
(m は必須です。そうでない場合は、「初期ヒープが小さすぎます」という別のエラーが発生します) は機能します。
これが他の AV 製品で起こるかどうかはわかりませんが、おそらく AV プログラムがすべてのアドレス空間で小さなメモリ ブロックを予約しており、それによって 1 つの非常に大きな割り当てが妨げられているためにこの問題が発生していると考えられます。
VM引数はEclipseで機能しました。Eclipse バージョン 3.4 を使用している場合は、次の手順を実行します。
に行く Run --> Run Configurations -->
次に、Maven build の下のプロジェクトを選択します --> 次に、「JRE」タブを選択します --> 次に、次のように入力します -Xmx1024m
.
あるいは、次のようにすることもできます Run --> Run Configurations --> select the "JRE" tab -->
次に、「-」と入力しますXmx1024m
これにより、すべてのビルド/プロジェクトのメモリ ヒープが増加するはずです。上記メモリサイズは1GBです。必要に応じて最適化できます。
はい、付きます -Xmx
JVM 用にさらに多くのメモリを構成できます。メモリのリークや無駄が発生しないようにするためです。ヒープダンプを取得して使用します Eclipse メモリ アナライザー メモリ消費量を分析します。
オラクルからの推奨事項を追加したい トラブルシューティング 記事。
スレッド thread_name で例外が発生しました: java.lang.OutOfMemoryエラー:Java ヒープ領域
詳細メッセージ Java ヒープ スペースは、オブジェクトを Java ヒープに割り当てることができなかったことを示しています。このエラーは必ずしもメモリ リークを意味するものではありません
考えられる原因:
単純な構成の問題, 、指定されたヒープ サイズがアプリケーションにとって不十分な場合。
アプリケーションが意図せずオブジェクトへの参照を保持している, これにより、オブジェクトがガベージ コレクションされるのを防ぎます。
ファイナライザーの過剰な使用.
このエラーのもう 1 つの潜在的な原因は、ファイナライザーを過度に使用するアプリケーションで発生します。クラスにファイナライズ メソッドがある場合、その型のオブジェクトはガベージ コレクション時に領域が再利用されません。
後 ガベージコレクション, 、オブジェクトはキューに入れられます ファイナライズ, 、これは後で発生します。 ファイナライザー ファイナライゼーション キューにサービスを提供するデーモン スレッドによって実行されます。もし ファイナライザー スレッドがファイナライゼーション キューに追いつかないと、Java ヒープがいっぱいになり、このタイプの メモリ不足エラー 例外がスローされます。
この状況を引き起こす可能性のある 1 つのシナリオは、アプリケーションが 優先度の高いスレッド それが原因となる ファイナライズ ファイナライザー スレッドがそのキューを処理する速度よりも速い速度でキューが増加します。
以下の手順に従います。
開ける
catalina.sh
Tomcat/bin から。JAVA_OPTS を次のように変更します
JAVA_OPTS="-Djava.awt.headless=true -Dfile.encoding=UTF-8 -server -Xms1536m -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=256m -XX:MaxPermSize=256m -XX:+DisableExplicitGC"
Tomcat を再起動します
簡単な解決方法 OutOfMemoryError
Javaでは、JVMオプションを使用して最大ヒープサイズを増やすことです -Xmx512M
, 、これで OutOfMemoryError がすぐに解決されます。プロジェクトのサイズによっては簡単にメモリ不足になる可能性があるため、プロジェクトのビルド中に Eclipse、Maven、または ANT で OutOfMemoryError が発生した場合、これが私の推奨解決策です。
ここでは、JVM の最大ヒープ サイズを増やす例を示します。また、Java アプリケーションでヒープ サイズを設定する場合は、-Xmx と -Xms の比率を 1:1 または 1:1.5 に保つことをお勧めします。
export JVM_ARGS="-Xms1024m -Xmx1024m"
開発用のデフォルトでは、JVM は他のパフォーマンス関連機能に小さいサイズと小さい構成を使用します。ただし、本番環境では、たとえば次のように調整できます。(さらに、アプリケーション サーバー固有の構成が存在する可能性があります) -> (要求を満たすのに十分なメモリがまだなく、ヒープがすでに最大サイズに達している場合は、OutOfMemoryError が発生します)
-Xms<size> set initial Java heap size
-Xmx<size> set maximum Java heap size
-Xss<size> set java thread stack size
-XX:ParallelGCThreads=8
-XX:+CMSClassUnloadingEnabled
-XX:InitiatingHeapOccupancyPercent=70
-XX:+UnlockDiagnosticVMOptions
-XX:+UseConcMarkSweepGC
-Xms512m
-Xmx8192m
-XX:MaxPermSize=256m (in java 8 optional)
例えば:Linux プラットフォームでは、運用モードの推奨設定。
この方法でサーバーをダウンロードして設定した後、 http://www.ehowstuff.com/how-to-install-and-setup-apache-tomcat-8-on-centos-7-1-rhel-7/
1. setenv.sh ファイルをフォルダー /opt/tomcat/bin/ に作成します
touch /opt/tomcat/bin/setenv.sh
2.優先モードを設定するためのこのパラメータを開いて書き込みます。
nano /opt/tomcat/bin/setenv.sh
export CATALINA_OPTS="$CATALINA_OPTS -XX:ParallelGCThreads=8"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+CMSClassUnloadingEnabled"
export CATALINA_OPTS="$CATALINA_OPTS -XX:InitiatingHeapOccupancyPercent=70"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UnlockDiagnosticVMOptions"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseConcMarkSweepGC"
export CATALINA_OPTS="$CATALINA_OPTS -Xms512m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx8192m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MaxMetaspaceSize=256M"
3.service tomcat restart
JVM はヒープだけでなく、より多くのメモリを使用することに注意してください。たとえば、Javaメソッド、スレッドスタック、ネイティブハンドルは、ヒープとは別のメモリで割り当てられ、JVM内部データ構造が割り当てられます。
私はJavaヒープサイズから同じ問題に直面しました。
Java 5(1.5) を使用している場合、2 つの解決策があります。
jdk1.6 をインストールし、Eclipse の設定に移動して、インストールした jav1 1.6 の jre パスを設定するだけです。
VM 引数を確認して、そのままにしておきます。-xms512m -xmx512m -xx:maxpermsize = ... m(192m)として、VM引数に存在するすべての引数の下に1行を追加するだけです。
うまくいくと思います...
私はあなたが試すことができる他の場所を読みました - catch java.lang.OutOfMemoryError と catch ブロックで、大量のメモリを使用する可能性があることがわかっているすべてのリソースを解放し、接続を閉じることができます。 System.gc()
それから、やろうとしていたことを再試行してください。
別の方法はこれですが、これが機能するかどうかはわかりませんが、現在私のアプリケーションで機能するかどうかをテストしています。
このアイデアは、空きメモリを増やすことが知られている System.gc() を呼び出してガベージ コレクションを実行することです。メモリを大量に消費するコードが実行された後も、これを確認し続けることができます。
//Mimimum acceptable free memory you think your app needs
long minRunningMemory = (1024*1024);
Runtime runtime = Runtime.getRuntime();
if(runtime.freeMemory()<minRunningMemory)
System.gc();
実行時にメモリ使用量を監視する必要がある場合は、 java.lang.management
パッケージオファー MBeans
これは、VM 内のメモリ プール (Eden スペース、Tenured Generation など) やガベージ コレクションの動作を監視するために使用できます。
これらの MBean によって報告される空きヒープ領域は、特にアプリケーションが後で GC 処理されるオブジェクトを大量に生成する場合、GC の動作に応じて大きく異なります。考えられるアプローチの 1 つは、各フル GC の後に空きヒープ領域を監視することです。これを使用して、オブジェクトを永続化してメモリを解放するかどうかを決定できます。
最終的には、パフォーマンスが許容範囲内である限り、メモリ保持を可能な限り制限することが最善の策です。前のコメントで述べたように、メモリは常に制限されていますが、アプリにはメモリ枯渇に対処するための戦略が必要です。
デプロイメント状況でこれが必要な場合は、JVM にさまざまな引数をクロスで指定できるため、Java WebStart (ネットワーク バージョンではなく、「オンディスク」バージョンで - Java 6u10 以降で可能) の使用を検討してください。プラットフォームの方法。
それ以外の場合は、必要な引数を設定するオペレーティング システム固有のランチャーが必要になります。
この問題が Wildfly 8 および JDK1.8 で発生している場合は、PermGen 設定の代わりに MaxMetaSpace 設定を指定する必要があります。
たとえば、wildfly の setenv.sh ファイルに以下の設定を追加する必要があります。JAVA_OPTS="$JAVA_OPTS -XX:MaxMetaspaceSize=256M"
詳細については、こちらをご確認ください Wildfly ヒープの問題
NetBeans に関しては、最大ヒープ サイズを設定すると問題を解決できます。
「実行」に移動し、 --> 「プロジェクト構成の設定」 --> 「カスタマイズ」 --> ポップアップウィンドウの「実行」 --> 「VM オプション」 --> 「-Xms2048m -Xmx2048m」と入力します。 。
オブジェクトへの参照を割り当てて保持し続けると、メモリはいくらでもいっぱいになってしまいます。
1 つのオプションは、タブを切り替えたときに透明なファイルを閉じて開くことです (ファイルへのポインタのみを保持し、ユーザーがタブを切り替えると、すべてのオブジェクトを閉じて消去します...)ファイルの変更が遅くなります...ただし...)、メモリ上に保持できるファイルは 3 つまたは 4 つだけかもしれません。
他にすべきことは、ユーザーがファイルを開いてロードし、OutOfMemoryError をインターセプトした後、(ファイルを開くことができないため) そのファイルを閉じ、そのオブジェクトをクリーンアップして、未使用のものを閉じるようにユーザーに警告することです。ファイル。
仮想メモリを動的に拡張するというアイデアは問題を解決しません。マシンのリソースは限られているため、メモリの問題には注意して対処する必要があります(少なくとも、メモリの問題には注意する必要があります)。
メモリリークに関して私が見たいくつかのヒントは次のとおりです。
--> コレクションに何かを入れて、その後それを忘れた場合でも、そのコレクションへの強い参照がまだ残っていることに注意してください。そのため、コレクションを無効にするか、クリーンアップするか、コレクションに対して何らかの操作を行ってください...そうしないと、メモリ リークを見つけるのが難しくなります。
--> おそらく、弱い参照 (weakhashmap...) を持つコレクションを使用するとメモリの問題を解決できるかもしれませんが、 しなければならない 探しているオブジェクトが収集されているかもしれないので、注意してください。
--> 私が見つけたもう 1 つのアイデアは、最も使用されず透過的にロードされるデータベース オブジェクトに保存される永続的なコレクションを開発することです。おそらくこれが最善のアプローチでしょう...