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

2008-02-23 08:17:00来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

怎样在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; 

            } 

        } 

    }
			   
			   

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Spring2.0与BEA WebLogic Server的集成

下一篇:Hibernate中的Session什么时候关闭?