/home/by-natures/dev*

ソフトウェア開発者として働く人の技術的なメモ

PermGen 領域に OOM エラー

OOM エラーに出くわしたのですが、よく発生する Heap 領域のものとは違うエラーが発生しました:

java.lang.OutOfMemoryError: PermGen space

Hive 関係のアプリケーションで発生していて、temporary function を大量に利用する処理を入れたばかりだったので、temporary function によって読み込まれた JAR とクラスがこの PermGen 領域に加わり、OOM エラーが発生したようです。

PermGen の理解

"PermGen" の正確な理解が怪しかったので少し調べたところ、とても詳しく解説されているブログがありました:

d.hatena.ne.jp

PermGen 領域 HotSpot VM で利用されますが、通常のヒープ領域とは別に確保され、クラスやメソッドのデータ、及びそのメタデータが格納されるとあります。領域の拡張も -XX:PermSize-XX:MaxPermSize オプションなどで、ヒープ領域とは別に設定する必要があります。

jmap コマンドで稼働しているプロセスのメモリ情報が取得出来るので、今回はこれで PermGen に割り当てられているメモリ容量を確認して、-XX:MaxPermSize オプションで容量拡張しました。

$ sudo jmap -heap <プロセスID>

Java8 では PermGen -> Metaspace

この jmap コマンドですが、Java SE 8 で実行すると、以下のような結果になります:

$ sudo jmap -heap <プロセスID>
...

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 1073741824 (1024.0MB)
   NewSize                  = 22020096 (21.0MB)
   MaxNewSize               = 357564416 (341.0MB)
   OldSize                  = 45088768 (43.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
...

PermGen という言葉が見つからないのですが、Java8 では "Naive メモリ" という領域へ移動し、名前も Metaspace という名前に変更されています。これを詳しく解説されているブログがありました:

equj65.net

もやは -XX:MaxPermSize などの PermGen に関するオプションは意味がないようですが、デフォルトでは Metaspace には容量制限が実質ない状態なので、MaxMetaspace オプションを指定していなければ、今回のような OOM は発生しなさそうです。