在Java应用程序中使用JNI来监视CPU详解

浮夸_陈奕迅_

浮夸_陈奕迅_

2016-02-19 19:29

岁数大了,QQ也不闪了,微信也不响了,电话也不来了,但是图老师依旧坚持为大家推荐最精彩的内容,下面为大家精心准备的在Java应用程序中使用JNI来监视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的毫秒数。

  public staticnative long getProcessCPUTime();

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

  JNIEXPORT jlong JNICALL

  Java_com_vladium_utils_SystemInformation_getProcessCPUTime (JNIEnv * env, jclass cls)

  二、本地方法实现

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

  

JNIEXPORT jlong JNICALL Java_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 JNICALL JNI_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。

  

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)demojfcSwingSet2SwingSet2.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://m.tulaoshi.com/bianchengyuyan/)
展开更多 50%)
分享

猜你喜欢

在Java应用程序中使用JNI来监视CPU详解

编程语言 网络编程
在Java应用程序中使用JNI来监视CPU详解

在Delphi应用程序中使用DLL

Delphi
在Delphi应用程序中使用DLL

s8lol主宰符文怎么配

英雄联盟 网络游戏
s8lol主宰符文怎么配

在应用程序中和Applets小程序中使用archive

编程语言 网络编程
在应用程序中和Applets小程序中使用archive

在Access中使用系统表保存应用程序变量

编程语言 网络编程
在Access中使用系统表保存应用程序变量

lol偷钱流符文搭配推荐

英雄联盟 网络游戏
lol偷钱流符文搭配推荐

Java进阶 Java应用程序中动态分配CPU资源

编程语言 网络编程
Java进阶 Java应用程序中动态分配CPU资源

在桌面应用中使用JAVA DB

编程语言 网络编程
在桌面应用中使用JAVA DB

lolAD刺客新符文搭配推荐

英雄联盟
lolAD刺客新符文搭配推荐

PPT中保存字体样式

PPT中保存字体样式

Java实现用DOM文档和XML文件互换的操作

Java实现用DOM文档和XML文件互换的操作
下拉加载更多内容 ↓