OOM は開発者にとって最も恐れられる問題の 1 つと言えますが、その原因は基本的にコードまたは JVM パラメーターの設定にあります。
この記事では、Java プロセスが OOM をトリガーした後のトラブルシューティング方法について読者に説明します。
実稼働環境には畏敬の念を抱いているとよく言われますが、問題を迅速に解決することも畏敬の念の表れです
OOM は「Out Of Memory」の略で、メモリが使い果たされていることを意味します。 JVM にオブジェクトにスペースを割り当てるのに十分なメモリがなく、ガベージ コレクターにリサイクルするスペースがない場合、このエラーがスローされます。
OOM はなぜ発生しますか? 通常、これらの問題が原因で発生します
#メモリリーク: アプリケーションが解放されずに使用されるメモリこのメモリを使用すると、仮想マシンが再度使用できなくなります。このメモリはリークされます。申請者はもう使用されておらず、仮想マシンによって他の申請者に割り当てることはできないため
メモリ オーバーフロー: 要求されたメモリが、JVM が提供できるメモリ サイズを超えています。これは、アプリケーションと呼ばれます。オーバーフロー
メモリ リークは持続し、最終的にはオーバーフローします。この 2 つは因果関係があります。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 トラブルシューティングのアイデアについて説明します。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 の実行中に最もリソースを消費するオブジェクトを表示できます (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
メモリ割り当てが小さすぎるかどうかを確認します 明らかなオブジェクトがあるかどうかを確認します割り当て リリースは多数あり、リリースはありません。
JVM の現在のメモリ スナップショットをエクスポートし、JDK や MAT などのツールを使用してスナップショットを分析します
以上が質問者: オンラインで OOM に遭遇した場合、どうやって解決しますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。