雑記帳 2010年 4月第3週

2010/04/11 Sun.

明日には全快してくれれば助かるんだけど、どうにも怪しい。とりあえず全力で引きこもって、早く治ることを祈りましょう。

2010/04/12 Mon.

空咳が止まらない。別に喉の具合は悪くないんだけど、延々と空咳だけが出る。肺の具合が悪くなってたりするのか?

2010/04/13 Tue.

突発的に降りてきた仕様変更の修正を今日で終わらせる。試験項目は明日に書き始めりゃいいか。時間かからなそうだし。

2010/04/14 Wed.

適当に試験項目を54項目ほど挙げてみたものの、実施するのがメンドくなったので38項目に削減。1.5日で終わるかな。
明日は考課の関係で帰社する予定だけど、どうせ賞与なんて出るかも怪しいし、今さら考課なんてやる意味あるのか?

2010/04/15 Thu.

自社の朝は9時からだけど、タイムカードを無視するつもりなので10時出社。どうせ大して作業があるワケでもない。
無意味な考課表を適当に埋めて、やることが皆無になったために昼過ぎに帰ってしまうことにする。有休扱いでいいや。
で、帰りにビジネスシューズを一足だけ買っておく。靴の裏が磨り減って、雨の日がコケそうになるのが怖いんだよね。

2010/04/16 Fri.

午前中に仕様変更の試験が完了。午後は未解決の問題について調査。長期稼動時にメモリリークが起こってるのが問題。
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のログが確認できりゃいいや。

2010/04/17 Sat.

undefined.