Glassfishインスタンスは、しばらくの間2週間ごとにダウンしましたjava.lang.OutOfMemoryError: PermGen space
。PermGenスペースを512MBに増やし、メモリ使用量のダンプを開始しましjstat -gc
た。2週間後、PermGenスペースが着実に増加していることを示す次のグラフを思いつきました(x軸の単位は分、y軸はKBです)。
私はエラーを特定できるある種のプロファイリングツールを探し回ってみました。ここでSOが言及したjmapのスレッドは、非常に役立つことがわかりました。からダンプされた約14000行のうちjmap -permstats $PID
、約12500行が含まれgroovy/lang/GroovyClassLoader$InnerLoader
ており、独自のGroovyコードまたはGroovy自体からのある種のメモリリークを示しています。Groovyは関連するコードベースの1%未満を構成していることを指摘する必要があります。
以下の出力例:
class_loader classes bytes parent_loader alive? type
<bootstrap> 3811 14830264 null live <internal>
0x00007f3aa7e19d20 20 164168 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aa7c850d0 20 164168 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aa5d15128 21 181072 0x00007f3a9607f010 dead groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aad0b40e8 36 189816 0x00007f3a9d31fbf8 dead org/apache/jasper/servlet/JasperLoader@0x00007f3a7d0caf00
....
では、どのコードがこれを引き起こしているのかをもっと知るにはどうすればよいですか?
この記事から、Groovyコードがどこかに動的にクラスを作成していると推測します。そして、jmapからのダンプから、死んだオブジェクト/クラス(?)のほとんどが同じparent_loaderを持っていることがわかりますが、このコンテキストでそれが何を意味するのかはわかりません。ここから先に進む方法がわかりません。
補遺
後発者の場合、受け入れられた回答は問題を解決しないことを指摘する価値があります。クラス情報をあまり保存しないことで、再起動するまでに必要な期間を10倍に延長するだけです。私たちの問題を実際に修正したのは、それを生成したコードを取り除くことでした。メソッドとクラスのアノテーションとしてGroovyを使用してカスタム制約をスクリプト化できる、検証(契約による設計)フレームワークOValを使用しました。プレーンJavaで明示的な事前条件と事後条件を優先してアノテーションを削除するのは退屈でしたが、それで作業は完了しました。OVal制約がチェックされるたびに、新しい匿名クラスが作成されていて、何らかの形で関連するクラスデータがメモリリークを引き起こしていたのではないかと思います。