程式扎記: [ Java 代碼範本 ] 取得系統記憶體, CPU 相關使用資訊

標籤

2011年5月29日 星期日

[ Java 代碼範本 ] 取得系統記憶體, CPU 相關使用資訊


參考自 這理
前言 :
最近做個項目,就是要取得cpu佔有率等等的系統信息,一開始以為要用動態鏈接庫了,但後來發現可以像下面這樣做,不去調用jni,這樣省去了很多JNI 所帶來的 effort. 在Java中,可以獲得總的物理內存、剩餘的物理內存、已使用的物理內存等信息,下面例子可以取得這些信息,並且獲得在Windows下的內存使用率.

實作過程 :
首先編寫一個 MonitorInfoBean 類,用來裝載監控的一些信息,包括物理內存、剩餘的物理內存、已使用的物理內存、內存使用率等字段,該類的代碼如下 :
- MonitorInfoBean.java : 裝載監控的信息Bean
  1. package perf.beans;  
  2.   
  3. public class MonitorInfoBean {  
  4.       
  5.     /** */  
  6.     /** 可使用內存. */  
  7.     private long totalMemory;  
  8.   
  9.     /** */  
  10.     /** 剩餘內存. */  
  11.     private long freeMemory;  
  12.   
  13.     /** */  
  14.     /** 最大可使用內存. */  
  15.     private long maxMemory;  
  16.   
  17.     /** */  
  18.     /** 操作系統. */  
  19.     private String osName;  
  20.   
  21.     /** */  
  22.     /** 總物理內存. */  
  23.     private long totalMemorySize;  
  24.   
  25.     /** */  
  26.     /** 剩餘的物理內存. */  
  27.     private long freePhysicalMemorySize;  
  28.   
  29.     /** */  
  30.     /** 已使用的物理內存. */  
  31.     private long usedMemory;  
  32.   
  33.     /** */  
  34.     /** 線程總數. */  
  35.     private int totalThread;  
  36.   
  37.     /** */  
  38.     /** cpu使用率. */  
  39.     private double cpuRatio;  
  40.   
  41.     public long getFreeMemory() {  
  42.         return freeMemory;  
  43.     }  
  44.   
  45.     public void setFreeMemory(long freeMemory) {  
  46.         this.freeMemory = freeMemory;  
  47.     }  
  48.   
  49.     public long getFreePhysicalMemorySize() {  
  50.         return freePhysicalMemorySize;  
  51.     }  
  52.   
  53.     public void setFreePhysicalMemorySize(long freePhysicalMemorySize) {  
  54.         this.freePhysicalMemorySize = freePhysicalMemorySize;  
  55.     }  
  56.   
  57.     public long getMaxMemory() {  
  58.         return maxMemory;  
  59.     }  
  60.   
  61.     public void setMaxMemory(long maxMemory) {  
  62.         this.maxMemory = maxMemory;  
  63.     }  
  64.   
  65.     public String getOsName() {  
  66.         return osName;  
  67.     }  
  68.   
  69.     public void setOsName(String osName) {  
  70.         this.osName = osName;  
  71.     }  
  72.   
  73.     public long getTotalMemory() {  
  74.         return totalMemory;  
  75.     }  
  76.   
  77.     public void setTotalMemory(long totalMemory) {  
  78.         this.totalMemory = totalMemory;  
  79.     }  
  80.   
  81.     public long getTotalMemorySize() {  
  82.         return totalMemorySize;  
  83.     }  
  84.   
  85.     public void setTotalMemorySize(long totalMemorySize) {  
  86.         this.totalMemorySize = totalMemorySize;  
  87.     }  
  88.   
  89.     public int getTotalThread() {  
  90.         return totalThread;  
  91.     }  
  92.   
  93.     public void setTotalThread(int totalThread) {  
  94.         this.totalThread = totalThread;  
  95.     }  
  96.   
  97.     public long getUsedMemory() {  
  98.         return usedMemory;  
  99.     }  
  100.   
  101.     public void setUsedMemory(long usedMemory) {  
  102.         this.usedMemory = usedMemory;  
  103.     }  
  104.   
  105.     public double getCpuRatio() {  
  106.         return cpuRatio;  
  107.     }  
  108.   
  109.     public void setCpuRatio(double cpuRatio) {  
  110.         this.cpuRatio = cpuRatio;  
  111.     }  
  112. }  

接著編寫一個獲得當前的監控信息的接口,該類的代碼如下所示 :
- IMonitorService.java : 提供解耦合的介面
  1. package perf.proto;  
  2.   
  3. import perf.beans.MonitorInfoBean;  
  4.   
  5. public interface IMonitorService {  
  6.     /** *//** 
  7.      * 獲得當前監控對像. 
  8.      * @return 返回監測對象 
  9.      * @throws Exception 
  10.      */  
  11.     public MonitorInfoBean getMonitorInfoBean() throws Exception;  
  12. }  

該類的實現類MonitorServiceImpl如下所示 :
- MonitorServiceImpl.java : 獲取系統訊息的實作類別
  1. package perf.utils;  
  2.   
  3. import perf.beans.MonitorInfoBean;  
  4. import perf.proto.IMonitorService;  
  5. import java.io.InputStreamReader;  
  6. import java.io.LineNumberReader;  
  7. import sun.management.ManagementFactory;  
  8. import com.sun.management.OperatingSystemMXBean;  
  9.   
  10.   
  11. public class MonitorServiceImpl implements IMonitorService{  
  12.     public  static final int CPUTIME = 5000;  
  13.     private static final int PERCENT = 100;  
  14.     private static final int FAULTLENGTH = 10;  
  15.     private static String PROC_CMD = System.getenv("windir")  
  16.                                     + "\\system32\\wbem\\wmic.exe process get Caption,CommandLine,"  
  17.                                     + "KernelModeTime,ReadOperationCount,ThreadCount,UserModeTime,WriteOperationCount";  
  18.     private long[] initCpuInfo = null;  
  19.       
  20.     public MonitorServiceImpl(){  
  21.         try{  
  22.             initCpuInfo = readCpu(Runtime.getRuntime().exec(PROC_CMD));  
  23.         }catch(Exception e){  
  24.             e.printStackTrace();  
  25.             initCpuInfo = null;  
  26.         }  
  27.     }  
  28.       
  29.     @Override  
  30.     public MonitorInfoBean getMonitorInfoBean() throws Exception {  
  31.         int kb = 1024;  
  32.           
  33.         // 可使用內存  
  34.         long totalMemory = Runtime.getRuntime().totalMemory() / kb;  
  35.         // 剩餘內存  
  36.         long freeMemory = Runtime.getRuntime().freeMemory() / kb;  
  37.         // 最大可使用內存  
  38.         long maxMemory = Runtime.getRuntime().maxMemory() / kb;  
  39.   
  40.         OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory  
  41.                 .getOperatingSystemMXBean();  
  42.   
  43.         // 操作系統  
  44.         String osName = System.getProperty("os.name");  
  45.         // 總物理內存  
  46.         long totalMemorySize = osmxb.getTotalPhysicalMemorySize() / kb;  
  47.         // 剩餘的物理內存  
  48.         long freePhysicalMemorySize = osmxb.getFreePhysicalMemorySize() / kb;  
  49.         // 已使用的物理內存  
  50.         long usedMemory = (osmxb.getTotalPhysicalMemorySize() - osmxb  
  51.                 .getFreePhysicalMemorySize())  
  52.                 / kb;  
  53.   
  54.         // 獲得線程總數  
  55.         ThreadGroup parentThread;  
  56.         for (parentThread = Thread.currentThread().getThreadGroup(); parentThread  
  57.                 .getParent() != null; parentThread = parentThread.getParent())  
  58.             ;  
  59.         int totalThread = parentThread.activeCount();  
  60.   
  61.         double cpuRatio = 0;  
  62.         if (osName.toLowerCase().startsWith("windows")) {             
  63.             cpuRatio = this.getCpuRatioForWindows();  
  64.         }  
  65.           
  66.         // 返回對象  
  67.         MonitorInfoBean infoBean = new MonitorInfoBean();  
  68.         infoBean.setFreeMemory(freeMemory);  
  69.         infoBean.setFreePhysicalMemorySize(freePhysicalMemorySize);  
  70.         infoBean.setMaxMemory(maxMemory);  
  71.         infoBean.setOsName(osName);  
  72.         infoBean.setTotalMemory(totalMemory);  
  73.         infoBean.setTotalMemorySize(totalMemorySize);  
  74.         infoBean.setTotalThread(totalThread);  
  75.         infoBean.setUsedMemory(usedMemory);  
  76.         infoBean.setCpuRatio(cpuRatio);  
  77.         return infoBean;  
  78.     }  
  79.       
  80.     private double getCpuRatioForWindows() {  
  81.         try {  
  82.             if(initCpuInfo==nullreturn 0.0;  
  83.             // 取得進程信息  
  84.             //long[] c0 = readCpu(Runtime.getRuntime().exec(PROC_CMD));  
  85.             //Thread.sleep(CPUTIME);  
  86.             long[] c1 = readCpu(Runtime.getRuntime().exec(PROC_CMD));  
  87.             if (c1 != null) {  
  88.                 long idletime = c1[0] - initCpuInfo[0];  
  89.                 long busytime = c1[1] - initCpuInfo[1];  
  90.                 return Double.valueOf(  
  91.                         PERCENT * (busytime) / (busytime + idletime))  
  92.                         .doubleValue();  
  93.             } else {  
  94.                 return 0.0;  
  95.             }  
  96.         } catch (Exception ex) {  
  97.             ex.printStackTrace();  
  98.             return 0.0;  
  99.         }  
  100.     }  
  101.       
  102.     private long[] readCpu(final Process proc) {  
  103.         long[] retn = new long[2];  
  104.         try {  
  105.             proc.getOutputStream().close();  
  106.             InputStreamReader ir = new InputStreamReader(proc.getInputStream());  
  107.             LineNumberReader input = new LineNumberReader(ir);  
  108.             String line = input.readLine();  
  109.             if (line == null || line.length() < FAULTLENGTH) {  
  110.                 return null;  
  111.             }  
  112.             int capidx = line.indexOf("Caption");  
  113.             int cmdidx = line.indexOf("CommandLine");  
  114.             int rocidx = line.indexOf("ReadOperationCount");  
  115.             int umtidx = line.indexOf("UserModeTime");  
  116.             int kmtidx = line.indexOf("KernelModeTime");  
  117.             int wocidx = line.indexOf("WriteOperationCount");  
  118.             long idletime = 0;  
  119.             long kneltime = 0;  
  120.             long usertime = 0;  
  121.             while ((line = input.readLine()) != null) {  
  122.                 if (line.length() < wocidx) {  
  123.                     continue;  
  124.                 }  
  125.                 // 字段出現順序:Caption,CommandLine,KernelModeTime,ReadOperationCount,  
  126.                 // ThreadCount,UserModeTime,WriteOperation  
  127.                 String caption = Bytes.substring(line, capidx, cmdidx - 1).trim();  
  128.                 String cmd = Bytes.substring(line, cmdidx, kmtidx - 1).trim();  
  129.                 if (cmd.indexOf("wmic.exe") >= 0) {  
  130.                     continue;  
  131.                 }  
  132.                 // log.info("line="+line);  
  133.                 if (caption.equals("System Idle Process")  
  134.                         || caption.equals("System")) {  
  135.                     idletime += Long.valueOf(  
  136.                             Bytes.substring(line, kmtidx, rocidx - 1).trim())  
  137.                             .longValue();  
  138.                     idletime += Long.valueOf(  
  139.                             Bytes.substring(line, umtidx, wocidx - 1).trim())  
  140.                             .longValue();  
  141.                     continue;  
  142.                 }  
  143.   
  144.                 kneltime += Long.valueOf(  
  145.                         Bytes.substring(line, kmtidx, rocidx - 1).trim())  
  146.                         .longValue();  
  147.                 usertime += Long.valueOf(  
  148.                         Bytes.substring(line, umtidx, wocidx - 1).trim())  
  149.                         .longValue();  
  150.             }  
  151.             retn[0] = idletime;  
  152.             retn[1] = kneltime + usertime;  
  153.             return retn;  
  154.         } catch (Exception ex) {  
  155.             ex.printStackTrace();  
  156.         } finally {  
  157.             try {  
  158.                 proc.getInputStream().close();  
  159.             } catch (Exception e) {  
  160.                 e.printStackTrace();  
  161.             }  
  162.         }  
  163.         return null;  
  164.     }  
  165. }  

該實現類中需要用到一個自己編寫byte的工具類,該類的代碼如下所示 :
- Bytes.java : 解決 String.subString() 處理中文的問題 (將中文試為一個byte)
  1. package perf.utils;  
  2.   
  3. public class Bytes {  
  4.     public static String substring(String src, int start_idx, int end_idx){  
  5.         byte[] b = src.getBytes();  
  6.         String tgt = "";  
  7.         for(int i=start_idx; i<=end_idx; i++){  
  8.             tgt +=(char)b[i];  
  9.         }  
  10.         return tgt;  
  11.     }  
  12. }  

測試結果 :
測試我們可以建立一個 MonitorServiceImpl 類別的實例, 在一建立時例後 MonitorServiceImpl 會立即取得當下的 CPU 相關初始訊息. 接著我們讓當前線程 Sleep 6 秒後在呼叫 getMonitorInfoBean() 函式已取的相關系統訊息, 測試代碼如下 :
- TMain.java : 測試類別
  1. package perf.test;  
  2.   
  3. import perf.beans.MonitorInfoBean;  
  4. import perf.utils.MonitorServiceImpl;  
  5.   
  6. public class TMain {  
  7.     public static void main(String args[])  
  8.     {  
  9.         MonitorServiceImpl MSImpl = new MonitorServiceImpl();  
  10.         try {  
  11.             Thread.sleep(MonitorServiceImpl.CPUTIME);  
  12.             MonitorInfoBean bean = MSImpl.getMonitorInfoBean();  
  13.             System.out.println("OSName: "+bean.getOsName());  
  14.             System.out.println("CPU Ratio: "+bean.getCpuRatio());  
  15.             System.out.println("Available Mem in JVM: "+String.valueOf(bean.getTotalMemory()/1000.0)+" MB");  
  16.             System.out.println("Free Mem in JVM: "+bean.getFreeMemory()/1000.0+" MB");  
  17.             System.out.println("Max Available Mem for JVM: "+bean.getMaxMemory()/1000.0+" MB");  
  18.             System.out.println("============================");  
  19.             System.out.println("Total Pyysical Mem Size: "+bean.getTotalMemorySize()/1000.0+" MB");  
  20.             System.out.println("Total Physical Free Mem: "+bean.getFreePhysicalMemorySize()/1000.0+" MB");  
  21.             System.out.println("Total Physical Used Memory: "+bean.getUsedMemory()/1000.0+" MB");  
  22.             System.out.println("============================");  
  23.             System.out.println("Total Thread in Java: "+bean.getTotalThread());  
  24.         } catch (Exception e) {           
  25.             e.printStackTrace();  
  26.         }  
  27.           
  28.     }  
  29. }  

執行結果 :
OSName: Windows 7
CPU Ratio: 12.0
Available Mem in JVM: 79.296 MB
Free Mem in JVM: 55.281 MB
Max Available Mem for JVM: 932.096 MB
============================
Total Pyysical Mem Size: 4191.412 MB
Total Physical Free Mem: 1311.06 MB
Total Physical Used Memory: 2880.352 MB
============================
Total Thread in Java: 5

補充說明 :
[Windows 技巧] wmic 使用簡介
wmic 是 Microsoft Windows Management Instrument 的縮寫. 提供了 Console mode 一個強而有力的 administrator 管理工具. 包或系統管理, 遠端主機訊息獲取到你想不到的更改主機名稱等功能都可以達成. 而 wmic 可以在路徑 C:\Windows\System32\wbem 下找到 (wmic.exe)...
This message was edited 3 times. Last update was at 26/05/2011 15:07:17

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!