ホームページ  >  記事  >  Java  >  質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?

質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?

Java后端技术全栈
Java后端技术全栈転載
2023-08-17 16:38:451069ブラウズ

OOM は開発者にとって最も恐れられる問題の 1 つと言えますが、その原因は基本的にコードまたは JVM パラメーターの設定にあります。

この記事では、Java プロセスが OOM をトリガーした後のトラブルシューティング方法について読者に説明します。

実稼働環境には畏敬の念を抱いているとよく言われますが、問題を迅速に解決することも畏敬の念の表れです

質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?

OOM が起こる理由

OOM は「Out Of Memory」の略で、メモリが使い果たされていることを意味します。 JVM にオブジェクトにスペースを割り当てるのに十分なメモリがなく、ガベージ コレクターにリサイクルするスペースがない場合、このエラーがスローされます。

OOM はなぜ発生しますか? 通常、これらの問題が原因で発生します

  1. 割り当てが少なすぎます: JVM 初期化メモリが小さく、ビジネスで大量のメモリが使用されているか、さまざまな JVM 領域へのメモリ割り当てが不当です
  2. # #コードの脆弱性: 特定のオブジェクトが頻繁に適用されるが、使用されないまま解放されず、メモリが枯渇する

#メモリリーク: アプリケーションが解放されずに使用されるメモリこのメモリを使用すると、仮想マシンが再度使用できなくなります。このメモリはリークされます。申請者はもう使用されておらず、仮想マシンによって他の申請者に割り当てることはできないため

メモリ オーバーフロー: 要求されたメモリが、JVM が提供できるメモリ サイズを超えています。これは、アプリケーションと呼ばれます。オーバーフロー

メモリ リークは持続し、最終的にはオーバーフローします。この 2 つは因果関係があります。

一般的な OOM

より一般的な OOM タイプには、次のようなものがあります。

java.lang.OutOfMemoryError: PermGen space

Java7 永続生成 (メソッド領域) オーバーフロー。これは使用されます。データを格納します。クラス情報、定数、静的変数、仮想マシンによってロードされたジャストインタイム コンパイラによってコンパイルされたコードなど。クラスが初めてロードされるたびに、メタデータは永続的な世代に保存されます

通常、多数の Class オブジェクトまたは JSP ページに表示されるか、CgLib 動的プロキシ テクノロジの使用によって

-XX: PermSize および -XX を渡すことができます。 : MaxPermSize メソッド領域のサイズを変更します

Java8 が永続世代をメタスペースに変更すると、エラーが報告されます: java.lang.OutOfMemoryError: メタデータ スペース、メタスペース メモリが不足しており、デフォルトで動的に展開されます

java.lang.StackOverflowError

仮想マシンのスタック オーバーフローは、通常、## の存在によって発生します。プログラム内の #無限ループまたは深い再帰呼び出し 。スタック サイズが小さすぎると、オーバーフローが発生します。-Xss

を使用してスタック サイズを設定できます。仮想マシンはスタック オーバーフロー エラーをスローし、間違ったクラスが見つかる可能性があります。

java.lang.OutOfMemoryError: Java heap space

Java ヒープ メモリ オーバーフロー、オーバーフローの原因は一般的に次のとおりです。不当な JVM ヒープ メモリ設定またはメモリ リークにより、

メモリ リークが発生した場合は、ツールを使用して、リークしたオブジェクトから GC ルートまでの参照チェーンを表示できます。リークしたオブジェクトの型情報と GC ルート参照チェーン情報を把握することで、リークしたコードの場所を正確に特定できます。

メモリ リークがない場合、つまり、メモリ内のオブジェクトがまだ残っている必要があります。生きている場合は、仮想マシンのヒープ パラメータ (-Xmx および -Xms) をチェックして、仮想マシンのメモリを増やすことができるかどうかを確認する必要があります。

概要: メソッド領域とメソッド領域のオーバーフロー シナリオ仮想マシン スタックについては、この記事ではあまり説明しません。以下では主に、Java ヒープ スペースに関する一般的な OOM トラブルシューティングのアイデアについて説明します。

JVM メモリ分布を確認する

Java アプリケーションの PID が 15162 であるとします。コマンドを入力して 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.

By View JVM のメモリ割り当てとランタイムの使用状況により、メモリ割り当てが適切かどうかを判断できます

さらに、JVM の実行中に最もリソースを消費するオブジェクトを表示できます (jmap -histo:live 15162 | more

JVM メモリ オブジェクトのリストは次に従ってソートされています)オブジェクトによって占有されるメモリ サイズ

  • instances: インスタンスの数
  • #bytes: 単位バイト
  • クラス名: クラス名
質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?

CustomObjTest オブジェクト インスタンスと過剰なメモリ使用量

## は明らかです。 #残念ながら、この解決策には限界があります。オブジェクトによる過剰なメモリ使用の問題のトラブルシューティングしかできないためです。

ここで、「[」は配列を表します。たとえば、「[C」は Char 配列を表し、「[」は配列を表します。 B" はバイト配列を表します。配列メモリが多すぎる場合、どのオブジェクトがそれを保持しているのかが分からないため、オフライン分析のためにメモリをダンプする必要があります

jmap -histo:live を実行します。このコマンドを実行すると、JVM は最初に GC をトリガーし、次に統計を収集します

ダンプ ファイル分析

ダンプ ファイルは Java プロセス ミラーのメモリであり、主に

システム情報仮想マシン プロパティ完全なスレッド ダンプすべてのクラスのステータスが含まれます。およびオブジェクト およびその他の情報

プログラムでメモリ オーバーフローまたは GC 例外が発生した場合、JVM に

メモリ リークがあることが疑われるため、ダンプ ファイルをエクスポートできます。分析

JVM起動パラメータ設定パラメータに以下を追加します

  • -XX:+HeapDumpOnOutOfMemoryError
  • -XX:HeapDumpPath=./(参数为 Dump 文件生成路径)

当 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 二进制文件在当前文件夹下

質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?

JvisualVM 分析

Dump 分析工具有很多,相对而言 JvisualVMJProfilerEclipse Mat,使用人群更多一些。下面以 JvisualVM 举例分析 Dump 文件

質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?

列举两个常用的功能,第一个是能看到触发 OOM 的线程堆栈,清晰得知程序溢出的原因

質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?

第二个就是可以查看 JVM 内存里保留大小最大的对象,可以自由选择排查个数

質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?

点击对象还可以跳转具体的对象引用详情页面

質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?

文中 Dump 文件较为简单,而正式环境出错的原因五花八门,所以不对该 Dump 文件做深度解析

注意:JvisualVM 如果分析大 Dump 文件,可能会因为内存不足打不开,需要调整默认的内存

概要レビュー

オンラインで JVM メモリ オーバーフローが発生した場合は、次の手順でトラブルシューティングを行うことができます

  1. jmap -heap メモリ割り当てが小さすぎるかどうかを確認します
  2. ##jmap -histo 明らかなオブジェクトがあるかどうかを確認します割り当て リリースは多数あり、リリースはありません。
  3. jmap -dump JVM の現在のメモリ スナップショットをエクスポートし、JDK や MAT などのツールを使用してスナップショットを分析します
上記で問題が見つからない場合は、アプリケーションがネットワーク接続やスレッドなどのリソースを絶えず作成していないかどうかを確認する必要があります。これにより、システム リソースが枯渇する可能性があります。

以上が質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はJava后端技术全栈で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。