在Java应用程序中监视CPU的使用
来源:互联网 发布:sas软件怎么安装 编辑:程序博客网 时间:2024/05/16 19:39
在Java应用程序中监视CPU的使用2003年6月16日 作者: Matrix-与Java共舞 浏览选项: 本文已被浏览 110 次 怎样在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 <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}); }[/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(用于与外部工具整合)。
from-javaworld.com javaresearch翻译
好消息是,可以采用一个更为可靠的方案:跳出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 <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}); }[/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(用于与外部工具整合)。
from-javaworld.com javaresearch翻译
- 在Java应用程序中监视CPU的使用
- 在Java应用程序中监视CPU的使用
- 在Java应用程序中监视CPU的使用
- [转]在Java应用程序中监视CPU的使用
- 在Java应用程序中监视CPU的使用--使用JNI编写自己的CPU监视器
- 监视 CPU 的使用
- 在Java应用程序中动态分配CPU资源
- 在应用程序中监视剪贴板的变化和内容
- 在应用程序中监视剪贴板的变化和内容
- 在应用程序中监视剪贴板的变化和内容
- 在应用程序中监视剪贴板的变化和内容
- Docker学习总结(24)——在Docker中监视Java应用程序的5种方法
- 如何在Java应用程序中动态分配CPU资源
- 如何在Java应用程序中动态分配CPU资源
- 教你在Java应用程序中动态的分配CPU资源
- java中Jnotify文件监视库的使用
- 在java中实现windows剪贴板监视
- 使用CPU计数器监视SQL Server性能的一点提示
- 搞定坏男人的最有效6大招数
- Java的内存泄漏
- Longhorn比XP快仅因注册表一处不同?
- 利用Java编写HTML文件分析程序
- 【收藏】Java用户界面本地化实例探索 ,读取资源包
- 在Java应用程序中监视CPU的使用
- 设计模式之外观(Facade)---对象结构型模式
- Eclipse及其插件介绍和下载
- java Game2D的网络游戏设计
- 自动截屏到文件的小程序
- 格式化数值和货币
- 数字证书介绍
- “网络蚂蚁”的Java实现
- COM初探(四)——本地EXE COM服务器