jvm GC が頻繁に発生する問題を解決する

1. フルGCが頻繁に発生する

(1) System.gc()を頻繁に実行する

(2) 古い世代の領域が急速に増大し、フル GC が自動的にトリガーされます。これは主に、新しい世代のメモリ領域が不足しているか、しきい値が小さいため、生き残ったオブジェクトが古い世代に継続的に移動されます。

2. 応用例

JVM 構成は次のとおりです: jre1.8、最大ヒープ領域は 3G、スレッド実行スタック サイズは 256K、新しい世代のサイズは 1G、古い世代のサイズは 2G。

その結果、次のエラーがログで見つかりました。

Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded

このエラーの理由は、gc 中に jvm が時間の 98% 以上を使用してヒープ領域の 2% 未満を解放すると、この例外が報告されるためです。

これは実際には、jvm が OutOfMemory 例外の発生を予測し、この例外を早期にスローするためです。これは、JVM にメモリ領域がないという意味ではありません。

そのため、Tomcat の起動パラメータに -XX:-UseGCOverheadLimit パラメータを追加して、JVM の予測機能をオフにします。

再度観察してみると、すぐに java.lang.OutOfMemoryError 例外が発生していることが分かりましたが、同時に若い世代の GC が非常に頻繁に行われており (下図参照)、まだメモリが大量に残っていることがわかりました。 GC が発生する前の若い世代のメモリ内のスペース。ビジネスコード内で System.gc() が実行され、手動で GC がトリガーされている疑いがあります。

-XX:+DisableExplicitGC を Tomcat 起動パラメータに追加して、手動 GC をオフにすることができます。つまり、ビジネスコード内で System.gc() の呼び出しがあっても GC は実行されません。これは、空調呼び出しを実行するのと同じです。

Tomcat を再起動して、再度観察してください。若い世代の GC は明らかに少なく、毎回、若い世代のメモリ領域がなくなると GC が開始されます。これは正常です。

しかし、この問題は実際には解決されておらず、GC は正常ですが、依然として OutOfMemoryError 例外が発生します。jstat -gc pid 3s を使用して観察すると、GC が発生した場合でも、新しい世代によって使用される S1 スペースは常に 0 であることがわかります。これは 2 つの問題を示しています。

1.S1 にメモリが割り当てられましたが、使用されていないため、単に無駄になっています。

2. 新しい世代で GC が発生すると、Eden と S0 に残存するオブジェクトの合計サイズが S1 のサイズより大きくなります。

次の図は、ヒープの割り当てを示しています。

この問題を一気に解決するには、ヒープ サイズを 5G、新世代では 3G、旧世代では 2G に設定します。同時にS0、S1のサイズも拡張します。最終的なパラメータは次のようになります。

-XX:-UseGCOverheadLimit -XX:+DisableExplicitGC -Xms5G -Xmx5G -XX:NewSize=3G -XX:MaxNewSize=3G -XX:SurvivorRatio=3

おすすめ

転載: blog.csdn.net/rogerxue12345/article/details/107863762