きどたかのブログ

いつか誰かがこのブログからトラブルを解決しますように。

今日のOOM解析(難易度 初級)

OutOfMemoryErrorがきた。
まずGCログを見る。
Javaヒープ足りてるな。
じゃあネイティブが怪しいんだろ。
それにしてもafの他にsys出てるけど何でSystem.gc()とか使ってるんだろう。


MQとDB2の設定をわかる範囲でかき集める。
一般的にネイティブは、Javaのクラス情報とかJITとか、
あとはMQのBINDING MODEとかDB2のtype2接続なんかで使われているので、
それと思われる情報を揃えていく。
MQはBINDING MODEじゃないっぽい。
DB2はtype2とtype4のようだ。


JOBLOGでMQ Provider Version確認。
JCLのSTEPLIBにはDB2のみ。MQのはない。
まあ、LINKLSTかも知れんので参考までに。データセット名からはバージョン推測出来ず。
javacoreからDB2のドライバーパス、それでバージョンも判明。
JOBLOGにドライバーバージョンもある。
type4のログも出てた。
ある例外のスタックトレースからtype2も使ってると判明。
JOBLOGからREGION=0M無制限。
javacoreからMQ_INSTALL_ROOTを発見、だけどWAS V7ではこれでネイティブライブラリは読まないので無視。


javacoreからRLIMIT関連を収集。
んー、潤沢。
てか無制限と言っていい。


本当にDB2かな?
そんなにネイティブ使うか?
参照圧縮もついてるし、2GBバーも気にしてたけど、RLIMIT_ASからして、2GBバーは関係なしだろ。
ヒープダンプでとりあえずコネクションやステートメントを数えてみる。
おやまあ少ない。
やっぱり違う気がするぞ。


OOMのメッセージを読み直す。
なんかこれ見たことないんだよな。
スレッド作るのに失敗。
ATTACHマクロ調べてみようか。
ちょっと期待してた情報がなかった。残念。


んー、ググる
製品違うけどそれっぽいの見つかった。
http://www-01.ibm.com/support/docview.wss?uid=swg21396557


MAXTREADSに達したっぽいな。
この資料ではRACFでやるユーザー毎の制限を変更しているが、BPXPRMxxでの制限のほうも調べておく。
SETOMVSなんて普段叩かないなぁ。よしよし動的にいけるいける。
それにしてもなんでそんなにスレッドが必要?


ヒープダンプからスレッドアナリシスをしてみる。もちろんMemory Analyzerで。
やけに多いんだよなぁ。
javacoreでも同じように多く、waitしてる。
SRのスレッド数とは桁違い。
普通のWASだとなんのスレッドか推測出来る。
こいつはWASじゃないぞ、きっと。


javacoreをもっとじっくり見てみる。
スレッドをスタートしとるやつがいた。
MQのクラスだけど、アプリケーションから呼ばれてる。
ああ、これJOBLOGにも出てたやつだわ。
ふーむ、アプリケーションの問題だね。
com.ibm.mq.MQSimpleConnectionManagerはMQのコネクションを管理するクラスなんだが、
これを使うと裏で監視のスレッドが走るようだ。
com.ibm.mq.PoolScavenger、こいつ自体はスレッドではないが、こいつが監視するスレッドを動かす。
こちらのクラスはAPIとして公開されているクラスではないので直接動かすことはない。
スタックトレースでは、MQSimpleConnectionManager.setActive(int mode)でPoolScavengerがスレッドを動かしてたはず。


Using JMS connection pooling with WebSphere Application Server and WebSphere MQ, Part 2
http://www.ibm.com/developerworks/websphere/library/techarticles/0709_titheridge/0709_titheridge.html


com.ibm.mq.MQSimpleConnectionManagerのJavaDoc
http://publib.boulder.ibm.com/infocenter/wmqv7/v7r0/topic/com.ibm.mq.javadoc.doc/WMQJavaClasses/com/ibm/mq/MQSimpleConnectionManager.html


Connection pooling in WebSphere MQ classes for Java
http://publib.boulder.ibm.com/infocenter/wmqv7/v7r0/topic/com.ibm.mq.csqzaw.doc/ja11210_.htm


スレッドが徐々にリークというオチか。
com.ibm.mq.MQSimpleConnectionManagerが膨大な数、ヒープダンプから観測された。
プールするやつが何匹も必要ないだろ。
なんで接続ファクトリーをルックアップしてないんだよ。


このようにところどころミスリードしてしまったが、本物の原因に辿り着けたと思う。


「違うと思う」となる部分がたまにあるけど、こればかりは経験だ。
論理的には起こりうることだけど、甚だ怪しいと感じる。


この問題について、自分は2回誤った結論に向かっていた。
ネイティブメモリと、スレッド数。
しかし、これを否定したのが経験。
ただし、この誤った結論もまた経験から生み出されていたりもする。
やっぱり思い込みはたまに修正せんとな。
OOMでJavaヒープじゃなかったからネイティブという思い込み。
JMSは接続ファクトリーをルックアップして、WASからの設定でプールを管理してるという思い込み。
一番初めのJOBLOGのメッセージをちゃんと調査せずに進めたことと、
JOBLOGのスタックトレースでMQからスレッドを作りに行ってるので安心して、
ユーザーアプリケーションから動かされている点に気付かなかったことは、慢心があったと言わざるを得ない。


ほぼ解決したと思っててもいいだろう。