OOM は、プログラムに脆弱性があることを意味します。コードまたは JVM パラメータ設定が原因である可能性があります。この記事では、Java プロセスが OOM をトリガーした場合のトラブルシューティング方法について読者に説明します。
実稼働環境には畏敬の念を抱いているとよく言われますが、問題を迅速に解決することも畏敬の念の表れです
: アプリケーションが解放されずに使用されるメモリこのメモリを使用すると、仮想マシンが再度使用できなくなります。このメモリはリークされます。申請者はもう使用されておらず、仮想マシンによって他の申請者に割り当てることはできないため
メモリ オーバーフロー: 要求されたメモリが、JVM が提供できるメモリ サイズを超えています。これは、アプリケーションと呼ばれます。オーバーフローメモリ リークは持続し、最終的にはオーバーフローします。この 2 つは因果関係があります。
一般的な OOMJava7 永続生成 (メソッド領域) オーバーフロー。仮想マシン クラス情報、定数、静的変数、ジャストインタイム コンパイラによってコンパイルされたコード、およびその他のデータ。クラスが初めてロードされるときは常に、メタデータは永続世代に保存されます。
一般に、多数の Class オブジェクトまたは JSP ページに表示されるか、CgLib 動的プロキシ テクノロジの使用によって
が発生します。メソッド領域のサイズは、-XX: PermSize
および -XX: MaxPermSize
Java8 によって永続世代がメタスペースに変更されます。エラーが報告されます:java.lang.OutOfMemoryError: Metadata space、メタスペースのメモリが不足しており、デフォルトで動的に拡張されます
java.lang.StackOverflowError
仮想マシン スタック オーバーフロー は通常、プログラム内に 無限ループまたは深い再帰呼び出し が存在することが原因で発生します。スタック サイズが小さすぎると、オーバーフローが発生します。-Xss
を使用してスタック サイズを設定できます。仮想マシンはスタック オーバーフロー エラーをスローし、間違ったクラスが見つかる可能性があります。
java.lang.OutOfMemoryError: Java heap space
Java ヒープ メモリ オーバーフロー、オーバーフローの原因は一般的に次のとおりです。不当な JVM ヒープ メモリ設定またはメモリ リークにより、
メモリ リークが発生した場合は、ツールを使用して、リークしたオブジェクトから GC ルートまでの参照チェーンを表示できます。リークしたオブジェクトの型情報と GC ルート参照チェーン情報を把握することで、リークしたコードの場所を正確に特定できます。
メモリ リークがない場合、つまり、メモリ内のオブジェクトがまだ残っている必要があります。生きている場合は、仮想マシンのヒープ パラメータ (-Xmx および -Xms) をチェックして、仮想マシンのメモリを増やすことができるかどうかを確認する必要があります。
概要: メソッド領域とメソッド領域のオーバーフロー シナリオ仮想マシン スタックについては、この記事ではあまり説明しません。以下では主に、Java ヒープ スペースに関する一般的な OOM トラブルシューティングのアイデアについて説明します。
Java アプリケーションの PID が 15162 であると仮定して、コマンド「Check JVM メモリ分布を確認する」を入力します。jmap -heap 15162
[xxx@xxx ~]# jmap -heap 15162 Attaching to process ID 15162, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.161-b12 using thread-local object allocation. Mark Sweep Compact GC Heap Configuration: MinHeapFreeRatio = 40 # 最小堆使用比例 MaxHeapFreeRatio = 70 # 最大堆可用比例 MaxHeapSize = 482344960 (460.0MB) # 最大堆空间大小 NewSize = 10485760 (10.0MB) # 新生代分配大小 MaxNewSize = 160759808 (153.3125MB) # 最大新生代可分配大小 OldSize = 20971520 (20.0MB) # 老年代大小 NewRatio = 2 # 新生代比例 SurvivorRatio = 8 # 新生代与 Survivor 比例 MetaspaceSize = 21807104 (20.796875MB) # 元空间大小 CompressedClassSpaceSize = 1073741824 (1024.0MB) # Compressed Class Space 空间大小限制 MaxMetaspaceSize = 17592186044415 MB # 最大元空间大小 G1HeapRegionSize = 0 (0.0MB) # G1 单个 Region 大小 Heap Usage: # 堆使用情况 New Generation (Eden + 1 Survivor Space): # 新生代 capacity = 9502720 (9.0625MB) # 新生代总容量 used = 4995320 (4.763908386230469MB) # 新生代已使用 free = 4507400 (4.298591613769531MB) # 新生代剩余容量 52.56726495150862% used # 新生代使用占比 Eden Space: capacity = 8454144 (8.0625MB) # Eden 区总容量 used = 4029752 (3.8430709838867188MB) # Eden 区已使用 free = 4424392 (4.219429016113281MB) # Eden 区剩余容量 47.665996699370154% used # Eden 区使用占比 From Space: # 其中一个 Survivor 区的内存分布 capacity = 1048576 (1.0MB) used = 965568 (0.92083740234375MB) free = 83008 (0.07916259765625MB) 92.083740234375% used To Space: # 另一个 Survivor 区的内存分布 capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used tenured generation: # 老年代 capacity = 20971520 (20.0MB) used = 10611384 (10.119804382324219MB) free = 10360136 (9.880195617675781MB) 50.599021911621094% used 10730 interned Strings occupying 906232 bytes.
JVM メモリ割り当てとランタイム使用量をチェックすることで、次のことを確認できます。メモリ割り当てが適切かどうか
さらに、JVM の実行中に最もリソースを消費するオブジェクトを表示できます (jmap -histo:live 15162 | more
JVM メモリ オブジェクトのリストは次に従ってソートされています)オブジェクトによって占有されるメモリ サイズ
CustomObjTest
オブジェクト インスタンスと過剰なメモリ使用量
jmap -histo:live
を実行します。このコマンドを実行すると、JVM は最初に GC をトリガーし、次に統計を収集します。
システム情報、仮想マシンのプロパティ、完全なスレッド ダンプ、すべてのクラスとオブジェクトのステータスなどが含まれます。情報
いつプログラムでメモリ オーバーフローまたは GC 例外が発生した場合、JVM にメモリ リークがあると考えられます。その場合、分析のためにダンプ ファイルをエクスポートできます
次のパラメータを JVM 起動パラメータ設定に追加します当 JVM 发生 OOM 异常自动导出 Dump 文件,文件名称默认格式:
java_pid{pid}.hprof
上面配置是在应用抛出 OOM 后自动导出 Dump,或者可以在 JVM 运行时导出 Dump 文件
jmap -dump:file=[文件路径] [pid] # 示例 jmap -dump:file=./jvmdump.hprof 15162
在本地写一个测试代码,验证下 OOM 以及分析 Dump 文件
设置 VM 参数:-Xms3m -Xmx3m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ public static void main(String[] args) { List<Object> oomList = Lists.newArrayList(); // 无限循环创建对象 while (true) { oomList.add(new Object()); } }
通过报错信息得知,java heap space
表示 OOM 发生在堆区,并生成了 hprof 二进制文件在当前文件夹下
JvisualVM 分析
Dump 分析工具有很多,相对而言 JvisualVM、JProfiler、Eclipse Mat,使用人群更多一些。下面以 JvisualVM 举例分析 Dump 文件
列举两个常用的功能,第一个是能看到触发 OOM 的线程堆栈,清晰得知程序溢出的原因
第二个就是可以查看 JVM 内存里保留大小最大的对象,可以自由选择排查个数
点击对象还可以跳转具体的对象引用详情页面
文中 Dump 文件较为简单,而正式环境出错的原因五花八门,所以不对该 Dump 文件做深度解析
注意:JvisualVM 如果分析大 Dump 文件,可能会因为内存不足打不开,需要调整默认的内存
オンラインで JVM メモリ オーバーフローが発生した場合は、次の手順でトラブルシューティングを行うことができます
jmap -heap
メモリ割り当てが小さすぎるかどうかを確認します。jmap -histo
明らかに割り当てられすぎて解放されていないオブジェクトがないか確認します。 jmap -dump
JVM の現在のメモリ スナップショットをエクスポートし、JDK や MAT などのツールを使用してスナップショットを分析します。 以上が特定のグループへのインタビュー: オンラインで OOM に遭遇した場合、どのようにトラブルシューティングを行うべきですか?の解き方?どのようなオプションがありますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。