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

2016-02-19 19:29 1 1 收藏

岁数大了,QQ也不闪了,微信也不响了,电话也不来了,但是图老师依旧坚持为大家推荐最精彩的内容,下面为大家精心准备的在Java应用程序中使用JNI来监视CPU详解,希望大家看完后能赶快学习起来。

【 tulaoshi.com - 编程语言 】

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

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com/bianchengyuyan/)

来源:https://www.tulaoshi.com/n/20160219/1621113.html

延伸阅读
Java 平台一直都以其平台无关性自豪。虽然这种无关性有许多好处,但是它也使得编写与硬件交互的 Java 应用程序的过程变得相当复杂。在本文中,研究科学家蒋清野讨论了两个项目,它们通过提供使Java 应用程序可以使用 USB 设备的 API 而使这个过程变得更轻易。 虽然这两个项目仍然处于萌芽状态,但是它们都显示了良好的前景,并已经成为一些...
上网的朋友一定都用过网络蚂蚁(NetAnts)的吧?不知你在使用过程中有没有注意过,那就是如果你想调动两个“蚂蚁”为您效力是不可能的——它总会把新运行的关闭。而“蚂蚁”程序的妙处就在于:在重复运行“蚂蚁”时它不仅拒绝运行,而且能把已经运行的“蚂蚁”激活,这样用上面的程序就无能为力了。但事实上实现拒绝运行并激活已运行的程序有多种...
Java的线程调度操作在运行时是与平台无关的。一个多任务系统需要在任务之间实现QoS(Quality of Service)管理时,如果CPU资源的分配基于Java线程的优先级,那么它在不同平台上运行时的效果是很难预测的。本文利用协调式多任务模型,提出一个与平台无关、并且能在任务间动态分配CPU资源的方案。 现在,由于计算机系统已经从人机交互逐步向机机...
标签: PHP
  大多数开发者认为面相对象的程序设计(OOP)思想和PHP是一对矛盾,但实际上,PHP封装了开发者在其应用程序中使用OOP技术的所有功能。为了证明这一点,让我们举一个经典的Vehicle(车辆)例子,其PHP类如下: class Vehicle {    // Stuff goes here! } 在我们新建的Vehicle类中,用方法(即PHP函数)来联系我们的应用程序...
一、INI文件概述 WindowsINI文件,可解释为Windows初始化文件。它是一种专门用来保存应用程序初始化信息和运行环境信息的文本文件。例如Windows3.1中两个著名的INI文件win.ini和system.ini就在Windows启动时定义了Windows环境中鼠标响应速度、使用的外壳(shell)程序等设置。Windows系统附带的许多应用程序也都有自己的INI文件,例如控制...

经验教程

753

收藏

74
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部