您现在的位置:赛迪网>>技术应用>>J2EE

怎样在Java应用程序中监视CPU的使用状况
作者:Vladimir Roubtsov 发文时间:2005.06.09

怎样在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使用信息,这儿的要点是现在我们可以以编程方式记录该信息。对于长时间运行测试和服务器应用诊断程序,应该会派上用场。

(T117)





赛迪网推出“IT博客”,花不到一分钟就完成注册
评论】 【推荐】 【 】 【打印】 【关闭

·Linux专区· ·黑客攻防·

· 循序渐进教你LINUX之软件配置方法
· 解析Linux环境下的ReiserFS文件系统
· 制作个版本Linux启动盘的四种通行方法
· 新手入门:浅谈Linux的文件系统
· 循序渐进学习系列之Linux的软件配置
· 实战讲解防范网络钓鱼技术大全
· 穿梭于防火墙下的黑马 DBB后门程序
· ISP被要求协助清理Sober蠕虫病毒
· 2006年网络安全最大私募浮出水面
· SMTP安全手册 Sendmail服务器安全
· 新的验证技术能消灭垃圾邮件吗?
· 什么都想知道 反垃圾邮件技术完全解析
·中国信息化· ·成功案例·

· 2005年度CIO评选揭晓 关注信息化建设尖兵
· 专题策划:中国信息化盘点2005 展望2006
· 制造业基于知识管理的创新
· 信息化建设中的六类知识转移
· 看清潜在风险:科利华摘牌与教育信息化反思
· 姜奇平:信息化与后现代的统一战线

· 思科DWDM技术上海证券交易所应用案例
· 思科智能信息网络助美特斯邦威快速成长
· 思科网络在北京现代汽车公司的成功应用
· 亮剑汽车制造 打造随需而动的采购供应链
· HP Integrity为金保工程添砖加瓦
· 山东农行采用HP方案打造数据上收前置系统

本周文章排行


内容字典

J2EE:Java 2 Enterprise Edition(JAVA2企业版),使用Java进行企业开发的一套扩展标准,必须基于J2SE,提供一个基于组件设计、 开发、集合、展开企业应用的途径……
企业级API:使用该API很容易创建大型的商务和数据库应用程序。这类应用程序可在某个组织机构内或通过互联网与其它应用程序共享多媒体数据。迄今为止Java企业级API家族中已有四个成员。
线程:程序的基本执行单位。一个进程可以有若干个线程在并发运行,其中每个线程都执行不同的任务,如等待某些事件的发生,完成程序继续执行前无需完成的耗时性工作等……

您还可以阅读

· 用缓冲技术提高JSP应用的性能和稳定性
· 熟练使用J2ME在实际开发中的可选包MMAPI
· 了解J2ME在实际开发中的可选包MMAPI
· EJB应用开发的设计实例深入分析
· Tomcat与Java Web开发技术详解连载之三

社区推荐

· 教您如何使用消息驱动Beans(一)
· EJB核心技术及其应用系列专题之一
· EJB最佳实践:如何做实体bean的保护
· DisplayTag在技术开发时的应用指南
· 周末巨献:有可能挑战Java优势的四种技术
· 争议话题:选择JSF不选Struts的十大理由
· 初学者入门教程:Shell编程概述(一)
· 详细讲解Quartz如何从入门到精通