怎样在Java应用程序中监视CPU的使用状况

发表于:2007-05-25来源:作者:点击数: 标签:javaCPU应用程序怎样使用
怎样在 Java 中得到CPU的使用情况呢?这儿同时有一个好消息和一个坏消息。坏消息是不能使用纯Java的方法得到CPU的使用。没有这方面的直接的API。一个建议的替代方法是通过Runtime.exec()确定JVM的进程ID(PID),调用外部的、平台相关的命令,然后在运行结果
怎样在Java中得到CPU的使用情况呢?这儿同时有一个好消息和一个坏消息。坏消息是不能使用纯Java的方法得到CPU的使用。没有这方面的直接的API。一个建议的替代方法是通过Runtime.exec()确定JVM的进程ID(PID),调用外部的、平台相关的命令,然后在运行结果中解析出感兴趣的PID。但是,这种方法并不理想。

好消息是,可以采用一个更为可靠的方案:跳出Java,写几行C代码,然后通过JNI进行整合。下面我将向你展示编写一个Win32平台的简单的JNI库是多么简单。

一般来说,JNI有点复杂。但是,如果你仅仅单向调用--从Java调用本地代码,并且仅使用基本型进行通讯--事情还是很简单的。有许多JNI方面的学习资料,所以这儿我就不介绍JNI的基础了。我仅介绍我的实现步骤。

一、在Java中声明JNI方法

开始,我创建一个声明了本地方法的类com.vladium.utils.SystemInformation,该方法返回当前进程已使用的CPU的毫秒数。

public staticnative long getProcessCPUTime();

使用JDK内置的javah工具产生将来本地代码实现使用的C头文件。

 

JNIEXPORT jlong
            JNICALLJava_com_vladium_utils_
            SystemInformation_getProcessCPUTime
            (JNIEnv * env, jclass cls)

二、本地方法实现

在大多数的Win32平台上,该方法可以使用GetProcessTimes()系统调用实现,差不多仅需要3行代码就可以了:

 

JNIEXPORT jlong
            JNICALLJava_com_vladium_utils_
            SystemInformation_getProcessCPUTime
            (JNIEnv * env, jclass cls)
            {
            FILETIME creationTime, exitTime,
            kernelTime, userTime; GetProcessTimes
            (s_currentProcess,
            & creationTime, & exitTime,
            & kernelTime, & userTime);
            return (jlong) ((fileTimeToInt64
            (& kernelTime) + fileTimeToInt64
            (& userTime)) /
            (s_numberOfProcessors * 10000));
            }

该方法首先累加用于执行当前进程的核心和用户代码耗费的时间,除以处理器的数目,并把结果转换到毫秒。fileTimeToInt64()是一个辅助函数,用于把FILETIME结构的数据转换为64位的整数。s_currentProcess 和 s_numberOfProcessors是全局变量,当JVM装载本地库时即初始化。

 

static HANDLE s_currentProcess;
            static int s_numberOfProcessors;
            JNIEXPORT jint JNICALLJNI_OnLoad
            (JavaVM * vm, void * reserved)
            {
            SYSTEM_INFO systemInfo;
            s_currentProcess
            = GetCurrentProcess ();
            GetSystemInfo (& systemInfo);
            s_numberOfProcessors
            = systemInfo.dwNumberOfProcessors;
            return JNI_VERSION_1_2;
            }

注意,如果你在UNIX平台上实现getProcessCPUTime(),你应该以getrusage系统调用开始。

三、调用本地方法

回到Java中,在SystemInformation类中,装载本地库(silib.dll on Win32)最好通过静态初始化代码块完成。

 

private static final
            String SILIB = "silib";
            static
            {
            try
            {
            System.loadLibrary (SILI;
            }
            catch (UnsatisfiedLinkError e)
            {
            System.out.println
            ("native lib '" + SILIB + "'
            not found in 'java.library.path':
            " + System.getProperty
            ("java.library.path"));
            throw e; // re-throw
            }
            }

注意,getProcessCPUTime()返回自JVM进程创建以来使用的CPU时间。就这个数据本身而言,对于这儿并没有太多的用处。我需要更有用的Java方法来记录不同的时刻的数据快照(data snapshots),并报告任何两个时间点之间CPU的使用。

 

public static final class
            CPUUsageSnapshot
            {
            private CPUUsageSnapshot
            (long time, long CPUTime)
            {
            m_time = time;
            m_CPUTime = CPUTime;
            }
            public final long m_time, m_CPUTime;
            }
            // end of nested class public
            static CPUUsageSnapshot
            makeCPUUsageSnapshot ()
            {
            return new CPUUsageSnapshot
            (System.currentTimeMillis (),
            getProcessCPUTime ());
            }
            public static double
            getProcessCPUUsage
            (CPUUsageSnapshot start,
            CPUUsageSnapshot end)
            { return ((double)(end.m_CPUTime
            - start.m_CPUTime)) /
            (end.m_time - start.m_time);
            }

四、一个简单的CPU监视程序

“CPU监视API”基本就完成了!最后,我创建了一个singleton的线程类CPUUsageThread,它自动地每过一个时间间隔(默认是0.5秒)就拍下一个数据快照,并报告给所有的CPU使用事件的监听者(Observer模式)。

 

public void run ()
            {
            while (! isInterrupted ())
            {
            final SystemInformation.
            CPUUsageSnapshot snapshot
            = SystemInformation.makeCPUUsageSnapshot ();
            notifyListeners (snapshot);
            try { sleep (sleepTime);
            }
            catch (InterruptedException e)
            {
            return;
            }
            }
            }

CPUmon类是一个示例的监听器,仅简单地把CPU的使用情况打印输出到System.out。

 

public static void
            main (String [] args) throws Exception
            {
            if (args.length == 0)
            throw new IllegalArgumentException
            ("usage: CPUmon
            <app_main_class> <app_main_args...>");
            CPUUsageThread monitor
            = CPUUsageThread.getCPUThreadUsageThread ();
            CPUmon _this = new CPUmon ();
            Class app = Class.forName (args [0]);
            Method appmain = app.getMethod
            ("main", new Class [] {String[].class});
            String [] appargs
            = new String [args.length - 1];
            System.arraycopy
            (args, 1, appargs, 0, appargs.length);
            monitor.addUsageEventListener (_this);
            monitor.start (); appmain.invoke
            (null, new Object [] {appargs});
            }

另外,为了能够在启动要监视的应用程序之前开始CPUUsageThread,CPUmon.main()包装了另一个Java主类。

作为演示,我运行CPUmon和JDK1.3.1的SwingSet2示例程序(不要忘了把silib.dll安装到OS的PATH环境变量或者java.library.path系统属性所覆盖的路径下):

 

>java -Djava.library.path=
            . -cp silib.jar;
            (my JDK install dir)\demo\jfc
            \SwingSet2\SwingSet2.jar CPUmon SwingSet2
            [PID: 339] CPU usage: 46.8%
            [PID: 339] CPU usage: 51.4%
            [PID: 339] CPU usage: 54.8%
            (while loading, the demo
            uses nearly 100% of one of
            the two CPUs on my machine)
            ...
            [PID: 339] CPU usage: 46.8%
            [PID: 339] CPU usage: 0%
            [PID: 339] CPU usage: 0%
            (the demo finished loading
            all of its panels and is mostly idle)
            ...
            [PID: 339] CPU usage: 100%
            [PID: 339] CPU usage: 98.4%
            [PID: 339] CPU usage: 97%
            (I switched to the ColorChooserDemo
            panel which ran a CPU-intensive
            animation that used both of my CPUs)
            ...
            [PID: 339] CPU usage: 81.4%
            [PID: 339] CPU usage: 50%
            [PID: 339] CPU usage: 50%
            (I used Windows NT Task Manager
            to adjust the CPU affinity for the
            "java" process to use a single CPU)
            ...

当然,我也可以通过任务管理器查看到CPU使用信息,这儿的要点是现在我们可以以编程方式记录该信息。对于长时间运行测试服务器应用诊断程序,应该会派上用场。

原文转自:http://www.ltesting.net

评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)