怎样在java中得到cpu的使用情况呢?这儿同时有一个好消息和一个坏消息。坏消息是不能使用纯java的方法得到cpu的使用。没有这方面的直接的api。一个建议的替代方法是通过runtime.exec()确定jvm的进程id(pid),调用外部的、平台相关的命令,例如ps,然后在运行结果中解析出感兴趣的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 (silib);
} 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。
[code] public static void main (string [] args) throws exception { if (args.length == 0) throw new illegalargumentexception ("usage: cpumon ");
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}); }[/code]
另外,为了能够在启动要监视的应用程序之前开始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使用信息,这儿的要点是现在我们可以以编程方式记录该信息。对于长时间运行测试和服务器应用诊断程序,迟早会派上用场。本文附带的完整的库中添加了其它一些有用的本地方法,其中一个可以得到进程的pid(用于与外部工具整合)。
闽公网安备 35060202000074号