
私たちの SAP システムの 1 つ (PI ABAP+JAVA スタック) でパフォーマンスの問題が発生していました。マシンに構成されている 64 GB 全体が消費されてしまいました (8 つのコアも同様)。誰もが Java の部分を疑っていますが、私は違うと思います。
Java サーバー ノードがメモリ不足エラーで再起動されました。hprof ファイルを確認すると、サーバー ノードに 3GB (-Xms と Xmx の両方) のヒープが構成されているのに、サイズが 1.2G (3 つのサーバー ノードの平均) しかないことがわかりました。この観察から、次の疑問が生じました。
Xms と Xmx が同じ値に設定されている場合、JVM は起動時にヒープ全体を割り当てられると読みました。その場合、サーバー ノードは最初から 3 GB のヒープを持つことになります。そうであれば、なぜそれが hprof ファイルに反映されないのでしょうか。または、hprof には実行時にオブジェクトに割り当てられたメモリのみが含まれている場合、サイズはヒープ メモリが空いている (50% 以上) ことを明確に示しています。それでは、OOM エラーはどのように発生するのでしょうか...!!..??
また、Linux ではメモリ オーバーコミットと呼ばれる動作が行われることも知っています。つまり、メモリは要求されたときにではなく、実際に使用されたときに提供されます。これがメモリ不足例外の原因となっているのでしょうか。たとえば、JVM が起動すると、OS は 3GB のメモリが割り当てられたと伝えますが、実際には必要になるまで延期します。JVM が実際にオブジェクトにメモリを割り当てようとする頃には、他のアプリケーションがメモリを使い果たしている可能性があります。これはあり得ることでしょうか...??
たとえ Java ノードにメモリ リークの問題があったとしても、それは 3 GB のヒープに限定されるのではないですか。64 GB の物理メモリ全体をどうやって占有できるのでしょうか...???
私が観察したもう 1 つの点は、スワップ領域が 50% しか使用されていないことです。
これについて何かヒントが…!
答え1
SAP OSS もこの問題を調査していました。今日、彼らから返信を受け取りました。私の観察は正しかったです。Java が原因ではありませんでした。ABAP スタックに何らかの問題があり、メモリが解放されていませんでした。ABAP ワーク プロセスを再起動すると、OS レベルでメモリが解放されました。
しかし、質問の強調表示された部分についても理解したいと思います。たとえば、このような状況が発生して JAVA OOM エラーが発生する可能性があるかどうかなどです...??..!!。この点に関する情報はすべて役立ちます。
答え2
オーバーコミットは、Linux のヒューリスティック モードでデフォルトで有効になっています。つまり、カーネルは通常オーバーコミットを許可します。つまり、プロセスがすべてのメモリを同時に使用し始めることがないように、要求するすべてのプロセスに実際に提供できる以上のメモリを約束します。サーバーでオーバーコミットが無効になっている可能性があります。次のコマンドを実行して確認できます。
$ cat /proc/sys/vm/overcommit_memory
値が 0 の場合、ヒューリスティック オーバーコミットがオンになります。
実際のメモリ使用量がシステムが提供できる RAM の量を超える状況が発生すると、カーネルは OOM キラーをアクティブ化し、メモリを解放するためにプロセスを強制終了しようとします。通常、大量の RAM を消費する最も新しいプロセスが強制終了されますが、これに頼ることはできません。大混乱を引き起こす可能性があります (実際に引き起こします)。/proc//oom_adj を調整することで、OOM の親和性を変更し、特定のプロセスを強制終了できます (たとえば、OOM がデータベースまたはその他の大量の RAM [ab]user を強制終了する状況を回避する場合)。
したがって、システムが OOM フェーズに入ると、Java プロセスは即座に終了する可能性があります。この場合、観察している Java ログに「メモリ不足」メッセージは表示されません。
Xmx と Xms の両方を同じ値に設定するとヒープのサイズ変更は防止されますが、Java プロセスが起動時にすべてのメモリを一度に使い始めるわけではありません。必要なだけの VIRT メモリが割り当てられますが、常駐データ セットは Xms まで増加せず、必要なだけ低いままになります。
仮想メモリに関して: カーネルは Java プロセスに要求する分 (Xmx + 追加の分) を約束 (オーバーコミット) しますが、そのメモリのすべてがすぐに割り当てられるわけではありません。現在のデータに必要な量だけが割り当てられ、その量は常駐セット サイズ (タスクが使用したスワップされていない物理メモリ) を観察することで確認できます。VIRT および RSS のサイズを確認するには、次のコマンドを実行します。
$ ps aux | egrep '(^USER|java)'
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
tomcat 10229 21.5 9.1 6813688 548344 ? Sl 09:01 1:10 ....java...
おそらく、観察されているエラーは、Java 仮想マシン プロセスで実行されているプログラムにヒープ領域が不足していることを示しています。Xmx 設定を増やして、アプリを再テストしてみてください。