明日には全快してくれれば助かるんだけど、どうにも怪しい。とりあえず全力で引きこもって、早く治ることを祈りましょう。
空咳が止まらない。別に喉の具合は悪くないんだけど、延々と空咳だけが出る。肺の具合が悪くなってたりするのか?
突発的に降りてきた仕様変更の修正を今日で終わらせる。試験項目は明日に書き始めりゃいいか。時間かからなそうだし。
適当に試験項目を54項目ほど挙げてみたものの、実施するのがメンドくなったので38項目に削減。1.5日で終わるかな。
明日は考課の関係で帰社する予定だけど、どうせ賞与なんて出るかも怪しいし、今さら考課なんてやる意味あるのか?
自社の朝は9時からだけど、タイムカードを無視するつもりなので10時出社。どうせ大して作業があるワケでもない。
無意味な考課表を適当に埋めて、やることが皆無になったために昼過ぎに帰ってしまうことにする。有休扱いでいいや。
で、帰りにビジネスシューズを一足だけ買っておく。靴の裏が磨り減って、雨の日がコケそうになるのが怖いんだよね。
午前中に仕様変更の試験が完了。午後は未解決の問題について調査。長期稼動時にメモリリークが起こってるのが問題。
Red Hatで使えそうな解析ツールも知らないため、hprofでヒープを調べるしかない。すると、スレッド絡みで怪しそうな箇所が。
HTTPで接続要求を受けた時にServletが動いて、そこからThread
を起動しているんだけど、そのスレッドでリークしてそう。
import java.util.HashMap; import java.util.Map; public class ServerCache { private static Map<String, Object> threadInfoMap = new HashMap<String, Object>(); public static Map<String, Object> getThreadInfoMap() { return threadInfoMap; } }
超適当だけど、サーバ側でキャッシュの情報をstatic
で持たせておく。で、Servletが呼び出したThread
からはこう使ってる。
public class ServletThread implements Runnable { public void run() { // do something // スレッド情報をキャッシュに登録 ServerCache.getThreadInfoMap().put(Long.toString(Thread.currentThread().getId()), new Object()); // do something } }
new Object()
については、まあ適当にスレッドの情報を持たせたBeanを突っ込むってことで。で、この周辺の処理がNGらしい。
どうにもThread#getId()
ってのは延々と一意な値を返し続けるみたいなのね。こんなコーディングをしたのは一体どこの誰だ。
Bean生成部のコメントを読むと、「同一IDには上書きする」って書いてあるけど、そもそもIDが重複することはないわけで。
実装者はスレッドIDが適当なところでサイクリックすると思っていたんだろう。うーん、この部分の試験はされてたのか?
実際に動かしてみると、延々とIDがインクリメントされていく。普通に考えたらそうだよな、Thread#getId()
って戻り値がlong
だし。
つーことは、サーバのインスタンスが起動している限りは延々とリークしていくわけじゃん。これは長期稼動には耐えられんわ。
で、本当にこの部分が問題で落ちているのかを確認するため、hprofを仕掛けた状態で週末を延々と稼動状態にさせておく。
多分日曜の午前1時くらいを目処にOutOfMemoryError
で落ちてくれるだろう。月曜日にhprofのログが確認できりゃいいや。
undefined.