- PR -

Tomcatのスレッド数のモニタリング

1
投稿者投稿内容
ひでぶ
会議室デビュー日: 2002/08/09
投稿数: 5
投稿日時: 2003-04-23 10:41
Solaris+Tomcat4.1.12+j2sdk1.4.1_01を使ってますが、時々動作不安定なときがあります。
OSレベルで取得できるものは、モニタリングしています。
Tomcatでのスレッド数やメモリの状態をモニタリングしようとしているのですが、
やり方がわかりません。
IplanetやJrunなどの商用のものを使ってたときは、モニタリング機能がついてたのですが。
コマンドレベルでも、何でも良いのでスレッド数や使用しているメモリの値を取得する方法をご存知の方がいたら教えてください。
よろしくお願いします

[ メッセージ編集済み 編集者: ひでぶ 編集日時 2003-04-23 10:42 ]
YOU@IT
ぬし
会議室デビュー日: 2002/03/29
投稿数: 284
お住まい・勤務地: 大阪
投稿日時: 2003-04-23 17:46
EclipseでプロファイルPlug-inがあります。

Tomcatに接続してスレッドやヒープの状態を監視できますよ。
ただ、少し使ってみた感じでは、かなり重くてもうひとつ実用的ではない気もしますが...

http://eclipsecolorer.sourceforge.net/

さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2003-04-24 00:16
JVMPI (Java Virtual Machine Profile Interface) というのがあって、これを使うと
自分で Profiler が作れます。

JVMPI では JVM からプロファイルに関連するイベントがとれます。スレッド数やメ
モリであれば、スレッドの開始・終了と GC の終了のイベントを使えばできます。

簡単なサンプルを添付しました。残念ながら JVMPI は Java では記述できず、C/C++
になります。これを実行するときには

java -Xrunthrdmon [クラス名]

とします。つまり -Xrun の後にライブラリ名を書くだけです。
Tomcat と一緒に実行するなら catalina.sh に記述します。

実行すると、実行した場所に threadmonitor.log というファイルを作成して、そこに
GC とスレッドのログを記述します。本当であれば、ちゃんとしたログにする必要があ
ると思いますが、サンプルということでご容赦ください。

一応 Makefile も添付しておきますが、Solaris の環境がないので試していません。
たぶん、大丈夫だと思いますが... Makefile の中の JDK_HOME はインストールした
場所に応じて書き換えてください。

# 私は Windows と Visual C++ で動作チェックをしました

この程度だとそれほど重くならずに使えると思います。

くわしくは JVMPI のリファレンスをご覧ください。
http://java.sun.com/j2se/1.4/ja/docs/ja/guide/jvmpi/jvmpi.html

また、私の Web で Profiler について講演した資料がありますので参考になさっ
てください。
http://www5.airnet.ne.jp/sakuraba/java/publication/20030414-JIAE-Seminar/20030414JIAE-profiler.pdf

thrdmon.cpp
コード:
#include <jvmpi.h>
#include <jni.h>

extern "C" { 

    static JavaVM* javaVM;
    static JVMPI_Interface *jvmpi_interface;
    JVMPI_RawMonitor data_access_lock;
    FILE *fp;

    void notifyGCStart(JVMPI_Event *event) {
        jvmpi_interface->RawMonitorEnter(data_access_lock);
    }

    void notifyGCFinish(JVMPI_Event *event) {
        fprintf(fp, "GC: objects %I64d objects space %I64d total space %I64d\n", 
               event->u.gc_info.used_objects, 
               event->u.gc_info.used_object_space,
               event->u.gc_info.total_object_space);

        jvmpi_interface->RawMonitorExit(data_access_lock);
    }

    void notifyThreadStart(JVMPI_Event *event) {
        jvmpi_interface->RawMonitorEnter(data_access_lock);

        fprintf(fp, "Thread Start: name [%s] thread group [%s] parent thread [%s] env ID %d\n", 
                event->u.thread_start.thread_name,
                event->u.thread_start.group_name,
                event->u.thread_start.parent_name,
                event->u.thread_start.thread_env_id);

        jvmpi_interface->RawMonitorExit(data_access_lock);
    }

    void notifyThreadEnd(JVMPI_Event *event) {
        jvmpi_interface->RawMonitorEnter(data_access_lock);

        fprintf(fp, "Thread End: thread env ID %d\n", event->env_id);

        jvmpi_interface->RawMonitorExit(data_access_lock);
    }

    void notifyJVM_Shutdown(JVMPI_Event *event) {
        fclose(fp);
    }
    
    void notifyEvent(JVMPI_Event *event) {
        
        switch(event->event_type) {
        case JVMPI_EVENT_GC_START:
            notifyGCStart(event);
            break;

        case JVMPI_EVENT_GC_FINISH:
            notifyGCFinish(event);
            break;

        case JVMPI_EVENT_THREAD_START:
            notifyThreadStart(event);
            break;

        case JVMPI_EVENT_THREAD_END:
            notifyThreadEnd(event);
            break;

        case JVMPI_EVENT_JVM_INIT_DONE:
            break;

        case JVMPI_EVENT_JVM_SHUT_DOWN:
            notifyJVM_Shutdown(event);
            break;
        }            
    }
    
    JNIEXPORT jint JNICALL JVM_OnLoad(JavaVM *jvm, char *options, void *reserved) {
        // jvmpi のポインター取得
        if ((jvm->GetEnv((void **)&jvmpi_interface, JVMPI_VERSION_1)) < 0) {
            fprintf(stderr, "Error in obtaining jvmpi interface pointer\n");
            return JNI_ERR;
        } 
        
        JVMPI_RawMonitor data_access_lock = jvmpi_interface->RawMonitorCreate("data_access_lock");
      
        fp = fopen("threadmonitor.log", "w");

        // イベントコールバック関数の登録
        jvmpi_interface->NotifyEvent = notifyEvent;
        
        // イベントの設定
        jvmpi_interface->EnableEvent(JVMPI_EVENT_JVM_INIT_DONE, NULL);
        jvmpi_interface->EnableEvent(JVMPI_EVENT_JVM_SHUT_DOWN, NULL);

        jvmpi_interface->EnableEvent(JVMPI_EVENT_GC_START, NULL);
        jvmpi_interface->EnableEvent(JVMPI_EVENT_GC_FINISH, NULL);

        jvmpi_interface->EnableEvent(JVMPI_EVENT_THREAD_START, NULL);
        jvmpi_interface->EnableEvent(JVMPI_EVENT_THREAD_END, NULL);
        
        return JNI_OK;
    }
}



UNIX 用の Makefile
コード:
JDK_HOME=/usr/local/java/j2sdk1.4.1_01

INCLUDES= \
	-I$(JDK_HOME)/include \
	-I$(JDK_HOME)/include/solaris \

all : libthrdmon.so

libthrdmon.so: thrdmon.cpp
	cc -G $(INCLUDES) thrdmon.cpp -o $@

clean: 
	rm -f *.so *.o



Windows 用の Makefile
コード:
JDK_HOME = c:\progra~1\j2sdk1.4.1

INCLUDES = -I. -I$(JDK_HOME)\include -I$(JDK_HOME)\include\win32

SRC_DIR = .

all: thrdmon.dll

thrdmon.dll: $(SRC_DIR)\thrdmon.cpp
        cl -LDd -Zi -Zp1 $(INCLUDES) -Tp$(SRC_DIR)\thrdmon.cpp -o $@ /link /libpath:"C:\Progra~1\java\j2sdk1.4.2\lib" jvm.lib

clean:
	del *.lib
        del *.dll
        del *.ilk
        del *.pdb
        del *.obj
        del *.exp







1

スキルアップ/キャリアアップ(JOB@IT)