测量Java应用程序的CPU和内存占用率

欢迎进入Java社区论坛,与200万技术人员互动交流 >>进入

最重要的方法是getProcessCPUTime(),它会返回当前进程的CPU时间(内核和用户)的毫秒数,或者是PID在初始化期间被传送给本机库的进程所消耗的CPU时间。返回的值应该根据系统的处理器的个数进行调整;下面我们来看看这是如何在本机代码里做到的。我们用修改符native来声明这个方法,这意味着它必须在JNI代码里实现。getProcessCPUTime()方法用来给CPU的使用率数据进行快照,方式是将经过测量的CPU时间与当前的系统时间进行关联。这样的数据库快照在makeCPUUsageSnapshot()方法里进行,并输出一个CPUUsageSnapshot容器对象。这样,测量CPU使用率的原理就很容易理解了:我们按照给定的时间间隔进行两次CPU快照,按1.0的分数来计算两个时间点之间的CPU使用率,方式是两点所在的CPU时间差除以两点所在系统时间差。下面就是getProcessCPUUsage()方法的工作原理:

public static double getProcessCPUUsage (final CPUUsageSnapshot start, final CPUUsageSnapshot end) { if (start == null) throw new IllegalArgumentException (“null input: start”); if (end == null) throw new IllegalArgumentException (“null input: end”); if (end.m_time < start.m_time + MIN_ELAPSED_TIME) throw new IllegalArgumentException (“end time must be at least ” + MIN_ELAPSED_TIME + ” ms later than start time”); return ((double)(end.m_CPUTime – start.m_CPUTime)) / (end.m_time – start.m_time); }

只要我们知道分母里的快照之间的时间间隔,以及分子里进程花在活动状态上的CPU时间,我们就会得到所测量的时间间隔过程中进程的CPU使用率;1.0就代表所有处理器100%的使用率。

事实上这种方式可以用在所有版本的UNIX的ps工具和Windows的任务管理器上,这两个都是用于监视特定进程的CPU使用率的程序。很显然,时间间隔越长,我们得到的结果就越平均、越不准确。但是最小时差应该被强制输入getProcessCPUUsage()。这种限制的原因是某些系统上的System.currentTimeMillis()的解析度很低。Solaris 8操作系统提供了一个系统调用,用于从内核表里直接获得CPU使用率。出于这个目的,我们拥有的getProcessCPUPercentage()方法会以百分比的形式返回进程所使用的CPU时间。如果这个特性不被操作系统支持(比如在Windows下),那么JNI库就会根据我们应用程序的设计返回一个负值。

还有其他一些本机声明要在本机部分实现:

getCPUs()用来返回机器上处理器的个数 getMaxMem()用来返回系统上可用的最大物理内存 getFreeMem()用来返回系统上当前可用内存 getSysInfo()用来返回系统信息,包括一些硬件和操作系统的详细信息 getMemoryUsage()用来返回分配给进程的空间,以KB为单位(这些页面文件可能在内存里,也有可能不在内存里) getMemoryResident()用来返回当前进程驻留在内存里的空间,以KB为单位。

所有这些方法对于不同的Java开发人员来说常常都是非常有用的。为了确保本机JNI库被调入内存并在调用任何本机方法之前被初始化,这个库被加载到一个静态初始值里:

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 } }

在初始化一个.dll(或者.so)库之后,我们可以直接使用本机声明的方法:

final SystemInformation.CPUUsageSnapshot m_prevSnapshot =SystemInformation.makeCPUUsageSnapshot ();Thread.sleep(1000);final SystemInformation.CPUUsageSnapshot event = SystemInformation.makeCPUUsageSnapshot ();final long memorySize = SystemInformation.getMemoryUsage();final long residentSize = SystemInformation.getMemoryResident();long freemem = SystemInformation.getFreeMem()/1024;long maxmem = SystemInformation.getMaxMem()/1024;double receivedCPUUsage = 100.0 * SystemInformation.getProcessCPUUsage (m_prevSnapshot, event);System.out.println(“Current CPU usage is “+receivedCPUUsage+”%”);

现在让我们来分别看看针对Windows和Solaris的JNI本机实现。C头文件silib.h(列表B)能够用JDK里的Javah工具生成,或者手动编写。

列表B

/* DO NOT EDIT THIS FILE – it is machine generated */#include/* Header for class com_vladium_utils_SystemInformation */

#ifndef _Included_com_vladium_utils_SystemInformation#define _Included_com_vladium_utils_SystemInformation#ifdef __cplusplusextern “C” {#endif

/** Class: com_vladium_utils_SystemInformation* Method: getProcessID* Signature: ()I*/JNIEXPORT jintJNICALL Java_com_vladium_utils_SystemInformation_getProcessID (JNIEnv *, jclass);

/** Class: com_vladium_utils_SystemInformation* Method: getCPUs* Signature: ()I*/JNIEXPORT jintJNICALL Java_com_vladium_utils_SystemInformation_getCPUs (JNIEnv *, jclass);

/** Class: com_vladium_utils_SystemInformation* Method: getProcessCPUTime* Signature: ()J*/JNIEXPORT jlongJNICALL Java_com_vladium_utils_SystemInformation_getProcessCPUTime (JNIEnv *, jclass);

/** Class: com_vladium_utils_SystemInformation* Method: getProcessCPUUsage* Signature: ()D*/JNIEXPORT jdoubleJNICALL Java_com_vladium_utils_SystemInformation_getProcessCPUUsage (JNIEnv *, jclass);

/** Class: com_vladium_utils_SystemInformation* Method: getPagefileUsage* Signature: ()J*/JNIEXPORT jlongJNICALL Java_com_vladium_utils_SystemInformation_getPagefileUsage (JNIEnv *, jclass);

#ifdef __cplusplus}#endif#endif

[1][2][3][4][5]

青春气贯长虹,勇敢盖过怯懦,进取压倒苟安。

测量Java应用程序的CPU和内存占用率

相关文章:

你感兴趣的文章:

标签云: