在Java应用程序中监视CPU的使用

怎样在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的毫秒数。

publicstaticnativelonggetProcessCPUTime();



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

JNIEXPORTjlongJNICALLJava_com_vladium_utils_SystemInformation_getProcessCPUTime(JNIEnv*env,jclasscls)




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

JNIEXPORTjlongJNICALLJava_com_vladium_utils_SystemInformation_getProcessCPUTime(JNIEnv*env,jclasscls){
FILETIMEcreationTime,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装载本地库时即初始化。

staticHANDLEs_currentProcess;staticints_numberOfProcessors;JNIEXPORTjintJNICALLJNI_OnLoad(JavaVM*vm,void*reserved){
SYSTEM_INFOsystemInfo;
s_currentProcess=GetCurrentProcess();
GetSystemInfo(&systemInfo);
s_numberOfProcessors=systemInfo.dwNumberOfProcessors;returnJNI_VERSION_1_2;}


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

三、调用本地方法
回到Java中,在SystemInformation类中,装载本地库(silib.dllonWin32)最好通过静态初始化代码块完成。

privatestaticfinalStringSILIB="silib";
static{
try{
System.loadLibrary(SILIB);
}catch(UnsatisfiedLinkErrore){System.out.println("nativelib'"+SILIB+"'notfoundin'java.library.path':"+System.getProperty("java.library.path"));throwe;//re-throw}}



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

publicstaticfinalclassCPUUsageSnapshot{
privateCPUUsageSnapshot(longtime,longCPUTime){
m_time=time;
m_CPUTime=CPUTime;}publicfinallongm_time,m_CPUTime;}//endofnestedclasspublicstaticCPUUsageSnapshotmakeCPUUsageSnapshot(){returnnewCPUUsageSnapshot(System.currentTimeMillis(),getProcessCPUTime());}publicstaticdoublegetProcessCPUUsage(CPUUsageSnapshotstart,CPUUsageSnapshotend){return((double)(end.m_CPUTime-start.m_CPUTime))/(end.m_time-start.m_time);}




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

publicvoidrun(){
while(!isInterrupted()){
finalSystemInformation.CPUUsageSnapshotsnapshot=SystemInformation.makeCPUUsageSnapshot();notifyListeners(snapshot);
try{
sleep(sleepTime);}
catch(InterruptedExceptione){return;}}}



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

[code]publicstaticvoidmain(String[]args)throwsException{if(args.length==0)thrownewIllegalArgumentException("usage:CPUmon<app_main_class><app_main_args>");<br>CPUUsageThreadmonitor=CPUUsageThread.getCPUThreadUsageThread();CPUmon_this=newCPUmon();<br>Classapp=Class.forName(args[0]);<br>Methodappmain=app.getMethod("main",newClass[]{String[].class});<br>String[]appargs=newString[args.length-1];System.arraycopy(args,1,appargs,0,appargs.length);monitor.addUsageEventListener(_this);monitor.start();appmain.invoke(null,newObject[]{appargs});}[/code]<br><br>另外,为了能够在启动要监视的应用程序之前开始CPUUsageThread,CPUmon.main()包装了另一个Java主类。<br>作为演示,我运行CPUmon和JDK1.3.1的SwingSet2示例程序(不要忘了把silib.dll安装到OS的PATH环境变量或者java.library.path系统属性所覆盖的路径下):<br><br>&gt;java-Djava.library.path=.-cpsilib.jar;(myJDKinstalldir)\demo\jfc\SwingSet2\SwingSet2.jarCPUmonSwingSet2<br><br>[PID:339]CPUusage:46.8%<br>[PID:339]CPUusage:51.4%<br>[PID:339]CPUusage:54.8%<br>(whileloading,thedemousesnearly100%ofoneofthetwoCPUsonmymachine)<br>...<br>[PID:339]CPUusage:46.8%<br>[PID:339]CPUusage:0%<br>[PID:339]CPUusage:0%<br>(thedemofinishedloadingallofitspanelsandismostlyidle)<br>...<br>[PID:339]CPUusage:100%<br>[PID:339]CPUusage:98.4%<br>[PID:339]CPUusage:97%<br>(IswitchedtotheColorChooserDemopanelwhichranaCPU-intensive<br>animationthatusedbothofmyCPUs)<br>...<br>[PID:339]CPUusage:81.4%<br>[PID:339]CPUusage:50%<br>[PID:339]CPUusage:50%<br>(IusedWindowsNTTaskManagertoadjusttheCPUaffinityforthe<br>"java"processtouseasingleCPU)<br>...<br><br>当然,我也可以通过任务管理器查看到CPU使用信息,这儿的要点是现在我们可以以编程方式记录该信息。对于长时间运行测试和服务器应用诊断程序,迟早会派上用场。本文附带的完整的库中添加了其它一些有用的本地方法,其中一个可以得到进程的PID(用于与外部工具整合)。<br>from-javaworld.comjavaresearch翻译</app_main_args></app_main_class>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值