Java仮想マシンの仕様は、JVMメモリがヒープ、スタック、プログラムカウンター、メソッドエリアなどのいくつかのブロックに分割されていることを規定しています。ホットスポットJVMの実装では、ヒープメモリは3つの部分、新世代、老齢、永続的なバンドに分割されます。永続的なバンドは、仕様で指定されたメソッド領域を実装し、メモリモデルのさまざまな部分に対応するOutOFMEMoryErrorエラーがあります。次に、別々に説明しましょう。ほとんどの開発者がこのエラーに遭遇したと思いますが、このエラーの理由は主に次の理由によって引き起こされます。
JVMメモリが小さすぎてプログラムがタイトではなく、ゴミが多すぎます。
OutOfMemoryErrorの例外にはいくつかの一般的な原因があります。
このエラーの共通エラープロンプト:
StackoverFlowerror
スタックオーバーフローJava.lang.StackoverFlowerrorエラーをスローします。これは、スタックの深さが、メソッドが実行されているときに仮想マシンによって許可された最大深度を超えるために発生します。この状況は通常、プログラムエラーのために発生します。たとえば、死んだ再帰を書くことはこの状況を引き起こす可能性があります。この状況では、コードを使用してメモリオーバーフローをシミュレートします。
Java.util。*をインポートします。 java.lang。*をインポートします。 public class ooomtest {public void stackoverflowmethod(){stackoverflowmethod(); } public static void main(string ... args){ooomtest ooom = new oomtest(); ooom.StackOverFlowMethod(); }}上記のコードを実行すると、次の例外がスローされます。
スレッド「Main」Java.lang.StackoverFlowerror at ooomtest.stackoverflowmethod(oomtest.java:6)の例外
ヒープオーバーフロー(OutOfMemoryError:Java Heap Space)
ヒープメモリがオーバーフローすると、仮想マシンはjava.lang.outofmemoryerror:javaヒープスペースをスローします。これが発生した場合、メモリがオーバーフローしたときに生成されたダンプファイルに基づいて特異的に分析する必要があります(-xx: +heapdumponoutofmemoryerrorjvm起動パラメーターを追加する必要があります)。そのような問題が発生した場合、それはメモリリークまたはメモリオーバーフローである可能性があります。
メモリが漏れている場合、リークされたオブジェクトがGCルートでどのように参照されるかを調べ、参照チェーンを介したリークの原因を分析する必要があります。
メモリオーバーフローの問題がある場合、それは多くの場合、プログラムが仮想マシン用に構成するメモリよりも多くのメモリを必要とするためです。この場合、-XMXを使用してこの問題を解決できます。
以下に、次のコードを使用して、この状況のオーバーフローを示します。
Java.util。*をインポートします。 java.lang。*をインポートします。 public class ooomtest {public static void main(string ... args){list <byte []> buffer = new arrayList <byte []>(); buffer.add(new byte [10*1024*1024]); }}上記のコードを次のコマンドで実行します。
Java -verbose:gc -xmn10m -xms20m -xmx20m -xx:+printgc ooomtest
プログラムは次の情報を入力します。
[GC 1180K-> 366K(19456K)、0.0037311秒] [フルGC 366K-> 330K(19456K)、0.0098740秒] [フルGC 330K-> 292K(19456K)、0.0090244秒]例外 "Main.Java.Lang. oomtest.main(oomtest.java:7)
実行中の結果から、JVMがマイナーGCを1回、2回主要なGCを実行したことがわかります。主要なGCの出力から、GC後の古い領域の使用率は134Kであり、バイト配列が10mであることがわかります。これは、古い世代の空間よりも大きくなるため、例外が投げられます。 -XMS21Mおよび-XMX21Mが調整されている場合、GC操作はトリガーされず、例外もありません。
上記の実験を通じて、結論が側面から検証されました。オブジェクトが新世代の残りの記憶よりも大きい場合、老年に直接配置されます。老年の残りの記憶をまだ置くことができない場合、ガベージコレクションがトリガーされます。コレクション後も置くことができない場合は、メモリオーバーフロー例外がスローされます。
Permgenスペース
Hotspot JVMは、永続的なバンドを介してJava仮想マシン仕様のメソッド領域を実装し、ランタイム定数プールがメソッドエリアに保存されることを知っています。したがって、永続的なバンドオーバーフローは、ランタイム一定のプールオーバーフローであるか、メソッド領域に保存されているクラスオブジェクトが時間内にリサイクルされないか、クラス情報が占めるメモリが構成を超えている場合があります。永続バンドがオーバーフローすると、java.lang.outofmemoryerror:permgenスペースが投げられます。
作業中、次のシナリオでこの問題を経験するかもしれません。
一部のアプリケーションサーバーのホット展開を使用する場合、ホットデプロイメントに数回遭遇し、そのメモリがオーバーフローすることがわかります。これは、ホット展開のたびに、元のクラスがアンインストールされていないためです。
アプリケーション自体が大きく、より多くのクラスライブラリを含む場合、この問題は、永続的なバンド(-XX:Permsizeと-XX:MaxPermsizeによって設定)に割り当てるメモリが比較的小さい場合にも発生する可能性があります。
SpringやHibernateなどの一部のサードパーティフレームワークはすべて、バイトコード生成テクノロジー(CGLIBなど)を介していくつかの拡張機能を実装しています。
Javaの文字列定数が一定のプールに配置されていることがわかっています。 string.intern()メソッドが実行されると、この文字列に等しいオブジェクトが定数プールに保存されているかどうかを確認します。存在する場合は、定数プールのオブジェクトへの参照を直接返します。存在しない場合は、この文字列を最初に定数プールに追加してから、参照を文字列に返します。次に、string.internメソッドを介して実行時に一定の領域のオーバーフローをシミュレートできます。次のコードを使用して、この状況をシミュレートしましょう。
Java.util。*をインポートします。 java.lang。*をインポートします。 public class ooomtest {public static void main(string ... args){list <string> list = new arraylist <string>(); while(true){list.add(uuid.randomuuid()。toString()。intern()); }}}上記のコードを次のコマンドで実行します。
Java -verbose:gc -xmn5m -xms10m -xmx10m -xx:maxpermsize = 1m -xx:+printgc ooomtest
実行後の入力を以下の図に示します。
スレッドの例外 "main" java.lang.outofmemoryerror:java.lang.string.intern(native method)のpermgenスペースoomtest.main(oomtest.java:8)
上記のコードを介して、ランタイム中に一定のプールオーバーフローを正常にシミュレートしました。出力のパーマン空間から、永続的なバンドが実際にあふれていることがわかります。これは、前述のように、ホットスポットJVMが永続的なバンドを通じてメソッド領域を実装するという声明も検証していることがわかります。
outofmemoryerror:ネイティブスレッドを作成できません
最後に、java.lang.outofmemoryerror:natvieスレッドを作成できないエラーを見てみましょう。これが起こると、通常、次の2つの状況によって引き起こされます。
プログラムによって作成されたスレッドの数は、オペレーティングシステムの制限を超えています。 Linuxシステムの場合、Ulimit -Uを介してこの制限を表示できます。
仮想マシンに割り当てられたメモリは大きすぎるため、スレッドを作成するときに必要なネイティブメモリが少なすぎます。私たちは皆、オペレーティングシステムに各プロセスのメモリに制限があることを知っています。 JVMを開始するときは、プロセスを開始するのと同等です。プロセスの1つが4Gのメモリを占める場合、次の式で計算された残りのメモリは、スレッドスタックを構築するときに使用できるメモリです。スレッドスタックの利用可能なメモリの合計= 4G-(-XMXの値) - ( - xx:maxpermsizeの値) - プログラムカウンターで占めるメモリは、上記の式で-xmxとmaxpermsizeの値が大きいほど、スレッドスタックで使用可能なスペースが小さいことが示されています。 -XSSパラメーターによって構成されたスタック容量が変更されていない場合、作成できるスレッドの数は小さくなります。したがって、この状況のためにネイティブスレッドを作成することが不可能な場合は、プロセスが占有する総メモリを増やすか、より多くのスレッドを作成する目的を達成するために-XMXまたは-XSSを減らします。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。