1. 程式人生 > >Linux下java獲取CPU、記憶體、磁碟IO、網路頻寬使用率

Linux下java獲取CPU、記憶體、磁碟IO、網路頻寬使用率

原文地址:https://www.cnblogs.com/gisblogs/p/3985393.html

一、CPU

使用proc檔案系統,"proc檔案系統是一個偽檔案系統,它只存在記憶體當中,而不佔用外存空間。它以檔案系統的方式為訪問系統核心資料的操作提供介面。使用者和應用程式可以通過proc得到系統的資訊,並可以改變核心的某些引數。"

從/proc檔案系統獲取cpu使用情況:    cat /proc/stat

在Linux的核心中,有一個全 局變數:Jiffies。 Jiffies代表時間。它的單位隨硬體平臺的不同而不同。系統裡定義了一個常數HZ,代表每秒種最小時間間隔的數目。這樣jiffies的單位就是 1/HZ。Intel平臺jiffies的單位是1/100秒,這就是系統所能分辨的最小時間間隔了。每個CPU時間片,Jiffies都要加1。 CPU的利用率就是用執行使用者態+系統態的Jiffies除以總的Jifffies來表示。

 

在Linux系統中,CPU利用率的計算來源在/proc/stat檔案,這個檔案的頭幾行記錄了每個CPU的使用者態,系統態,空閒態等狀態下的不同的Jiffies,常用的監控軟體就是利用/proc/stat裡面的這些資料來計算CPU的利用率的。

包含了所有CPU活動的資訊,該檔案中的所有值都是從系統啟動開始累計到當前時刻。

 

[[email protected] LoadBalanceAlg]# cat /proc/stat
cpu  71095 55513 76751 2545622893 303185 4160 47722 0
cpu0 3855 1134 4284 159122519 3882 0 717 0
cpu1 4236 770 5837 159113370 11291 6 865 0
cpu2 4934 1142 5048 158991321 130622 362 2939 0
cpu3 2320 14774 5177 159111528 1417 8 1138 0
cpu4 2694 405 3086 159071174 56284 235 2477 0
cpu5 1701 886 2560 159129034 1316 2 849 0
cpu6 2937 450 2863 159068480 59183 228 2198 0
cpu7 916 316 2426 159130057 1682 1 933 0
cpu8 2543 50 3509 159122844 4467 1 2911 0
cpu9 4761 827 6296 159118849 4490 8 1086 0
cpu10 8517 4236 9148 159102063 9791 173 2382 0
cpu11 22001 29737 14602 159065992 2583 6 1382 0
cpu12 3453 150 3075 159113794 5387 1162 9276 0
cpu13 2120 424 3403 159126526 2608 7 1199 0
cpu14 2637 65 2663 159107796 6704 1914 14503 0
cpu15 1462 142 2763 159127539 1470 39 2859 0
intr 1636622296 1591605869 4 0 4 4 0 0 0 1 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 952 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1005479 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32763528 0 0 0 0 0 0 0 1697776 0 0 0 0 0 0 0 1556158 2 0 0 0 0 0 0 1598011 0 0 0 0 0 0 0 1287622 0 0 0 0 0 0 0 1522517 0 0 0 0 0 0 0 2467360 0 0 0 0 0 0 0 1116999 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 431778894
btime 1363058934
processes 279394
procs_running 1
procs_blocked 0

 

 

輸出解釋:
CPU 以及CPU0、CPU1、CPU2、CPU3每行的每個引數意思(以第一行為例)為:
引數 解釋
user (432661) 從系統啟動開始累計到當前時刻,使用者態的CPU時間(單位:jiffies) ,不包含 nice值為負程序。1jiffies=0.01秒
nice (13295) 從系統啟動開始累計到當前時刻,nice值為負的程序所佔用的CPU時間(單位:jiffies) 
system (86656) 從系統啟動開始累計到當前時刻,核心時間(單位:jiffies) 
idle (422145968) 從系統啟動開始累計到當前時刻,除硬碟IO等待時間以外其它等待時間(單位:jiffies) 
iowait (171474) 從系統啟動開始累計到當前時刻,硬碟IO等待時間(單位:jiffies) ,
irq (233) 從系統啟動開始累計到當前時刻,硬中斷時間(單位:jiffies) 
softirq (5346) 從系統啟動開始累計到當前時刻,軟中斷時間(單位:jiffies) 

CPU時間=user+system+nice+idle+iowait+irq+softirq

“intr”這行給出中斷的資訊,第一個為自系統啟動以來,發生的所有的中斷的次數;然後每個數對應一個特定的中斷自系統啟動以來所發生的次數。
“ctxt”給出了自系統啟動以來CPU發生的上下文交換的次數。
“btime”給出了從系統啟動到現在為止的時間,單位為秒。
“processes (total_forks) 自系統啟動以來所建立的任務的個數目。
“procs_running”:當前執行佇列的任務的數目。
“procs_blocked”:當前被阻塞的任務的數目。

 

那麼CPU利用率的計算方法:可以使用取兩個取樣點,計算其差值的辦法。

CPU利用率 = 1- (idle2-idle1)/(cpu2-cpu1)

 

參考:linux下如何獲取cpu的利用率

 

java中呼叫Linux的shell命令使用Process和Runtime

jdk1.6 API doc:

public class Runtimeextends Object
 

每個 Java 應用程式都有一個 Runtime 類例項,使應用程式能夠與其執行的環境相連線。可以通過getRuntime 方法獲取當前執行時。

應用程式不能建立自己的 Runtime 類例項。 

public abstract class Processextends Object
 

ProcessBuilder.start() 和Runtime.exec 方法建立一個本機程序,並返回 Process 子類的一個例項,該例項可用來控制程序並獲得相關資訊。

 

程式碼:

複製程式碼

<span style="font-size:14px;">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;

import org.apache.log4j.Logger;

/**
 * 採集CPU使用率
 */
public class CpuUsage extends ResourceUsage {

    private static Logger log = Logger.getLogger(CpuUsage.class);
    private static CpuUsage INSTANCE = new CpuUsage();
    
    private CpuUsage(){
    
    }
    
    public static CpuUsage getInstance(){
        return INSTANCE;
    }
    
    /**
     * Purpose:採集CPU使用率
     * @param args
     * @return float,CPU使用率,小於1
     */
    @Override
    public float get() {
        log.info("開始收集cpu使用率");
        float cpuUsage = 0;
        Process pro1,pro2;
        Runtime r = Runtime.getRuntime();
        try {
            String command = "cat /proc/stat";
            //第一次採集CPU時間
            long startTime = System.currentTimeMillis();
            pro1 = r.exec(command);
            BufferedReader in1 = new BufferedReader(new InputStreamReader(pro1.getInputStream()));
            String line = null;
            long idleCpuTime1 = 0, totalCpuTime1 = 0;    //分別為系統啟動後空閒的CPU時間和總的CPU時間
            while((line=in1.readLine()) != null){    
                if(line.startsWith("cpu")){
                    line = line.trim();
                    log.info(line);
                    String[] temp = line.split("\\s+"); 
                    idleCpuTime1 = Long.parseLong(temp[4]);
                    for(String s : temp){
                        if(!s.equals("cpu")){
                            totalCpuTime1 += Long.parseLong(s);
                        }
                    }    
                    log.info("IdleCpuTime: " + idleCpuTime1 + ", " + "TotalCpuTime" + totalCpuTime1);
                    break;
                }                        
            }    
            in1.close();
            pro1.destroy();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                StringWriter sw = new StringWriter();
                e.printStackTrace(new PrintWriter(sw));
                log.error("CpuUsage休眠時發生InterruptedException. " + e.getMessage());
                log.error(sw.toString());
            }
            //第二次採集CPU時間
            long endTime = System.currentTimeMillis();
            pro2 = r.exec(command);
            BufferedReader in2 = new BufferedReader(new InputStreamReader(pro2.getInputStream()));
            long idleCpuTime2 = 0, totalCpuTime2 = 0;    //分別為系統啟動後空閒的CPU時間和總的CPU時間
            while((line=in2.readLine()) != null){    
                if(line.startsWith("cpu")){
                    line = line.trim();
                    log.info(line);
                    String[] temp = line.split("\\s+"); 
                    idleCpuTime2 = Long.parseLong(temp[4]);
                    for(String s : temp){
                        if(!s.equals("cpu")){
                            totalCpuTime2 += Long.parseLong(s);
                        }
                    }
                    log.info("IdleCpuTime: " + idleCpuTime2 + ", " + "TotalCpuTime" + totalCpuTime2);
                    break;    
                }                                
            }
            if(idleCpuTime1 != 0 && totalCpuTime1 !=0 && idleCpuTime2 != 0 && totalCpuTime2 !=0){
                cpuUsage = 1 - (float)(idleCpuTime2 - idleCpuTime1)/(float)(totalCpuTime2 - totalCpuTime1);
                log.info("本節點CPU使用率為: " + cpuUsage);
            }                
            in2.close();
            pro2.destroy();
        } catch (IOException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            log.error("CpuUsage發生InstantiationException. " + e.getMessage());
            log.error(sw.toString());
        }    
        return cpuUsage;
    }

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        while(true){
            System.out.println(CpuUsage.getInstance().get());
            Thread.sleep(5000);        
        }
    }
}</span>

複製程式碼

二、記憶體

 

從/proc檔案系統獲取記憶體使用情況:   cat /proc/meminfo

 

MemTotal:      8167348 kB
MemFree:       4109964 kB
Buffers:         35728 kB
Cached:        1877960 kB
SwapCached:     159088 kB
Active:        3184176 kB
Inactive:       672132 kB
HighTotal:           0 kB
HighFree:            0 kB
LowTotal:      8167348 kB
LowFree:       4109964 kB
SwapTotal:    26738680 kB
SwapFree:     26373632 kB
Dirty:              40 kB
Writeback:           0 kB
AnonPages:     1872416 kB
Mapped:          24928 kB
Slab:           107804 kB
PageTables:      34612 kB
NFS_Unstable:        0 kB
Bounce:              0 kB
CommitLimit:  30822352 kB
Committed_AS:  5386080 kB
VmallocTotal: 34359738367 kB
VmallocUsed:    276892 kB
VmallocChunk: 34359460287 kB
HugePages_Total:     0
HugePages_Free:      0
HugePages_Rsvd:      0
Hugepagesize:     2048 kB

 

記憶體使用率 = 1 - MemFree/MemTotal

 

程式碼:

 

複製程式碼

<span style="font-size:14px;">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;

import org.apache.log4j.Logger;

/**
 * 採集記憶體使用率
 */
public class MemUsage extends ResourceUsage{

    private static Logger log = Logger.getLogger(MemUsage.class);
    private static MemUsage INSTANCE = new MemUsage();
    
    private MemUsage(){
    
    }
    
    public static MemUsage getInstance(){
        return INSTANCE;
    }
    
    /**
     * Purpose:採集記憶體使用率
     * @param args
     * @return float,記憶體使用率,小於1
     */
    @Override
    public float get() {
        log.info("開始收集memory使用率");
        float memUsage = 0.0f;
        Process pro = null;
        Runtime r = Runtime.getRuntime();
        try {
            String command = "cat /proc/meminfo";
            pro = r.exec(command);
            BufferedReader in = new BufferedReader(new InputStreamReader(pro.getInputStream()));
            String line = null;
            int count = 0;
            long totalMem = 0, freeMem = 0;
             while((line=in.readLine()) != null){    
                log.info(line);    
                String[] memInfo = line.split("\\s+");
                if(memInfo[0].startsWith("MemTotal")){
                    totalMem = Long.parseLong(memInfo[1]);
                }
                if(memInfo[0].startsWith("MemFree")){
                    freeMem = Long.parseLong(memInfo[1]);
                }
                memUsage = 1- (float)freeMem/(float)totalMem;
                log.info("本節點記憶體使用率為: " + memUsage);    
                if(++count == 2){
                    break;
                }                
            }
            in.close();
            pro.destroy();
        } catch (IOException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            log.error("MemUsage發生InstantiationException. " + e.getMessage());
            log.error(sw.toString());
        }    
        return memUsage;
    }
    
    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        while(true){
            System.out.println(MemUsage.getInstance().get());
            Thread.sleep(5000);
        }
    }
}</span>

複製程式碼

三、磁碟IO
 

使用iostat:

 

[[email protected] LoadBalanceAlg]# iostat -d -x
Linux 2.6.18-238.el5 (localhost.localdomain)    2013Äê03ÔÂ30ÈÕ


Device:         rrqm/s   wrqm/s   r/s   w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util
sda               0.09     0.28  0.02  0.03     0.92     2.57    60.71     0.00   63.28   3.33   0.02
sda1              0.00     0.00  0.00  0.00     0.00     0.00    24.40     0.00    2.59   2.53   0.00
sda2              0.09     0.28  0.02  0.03     0.92     2.57    60.76     0.00   63.36   3.34   0.02
sdb               0.03     0.72  0.04  0.53     2.57    10.04    22.09     0.01   17.36   5.12   0.29
sdb1              0.03     0.72  0.04  0.53     2.57    10.04    22.09     0.01   17.36   5.12   0.29
dm-0              0.00     0.00  0.07  1.30     2.63    10.40     9.53     0.03   24.95   2.15   0.29
dm-1              0.00     0.00  0.11  0.28     0.86     2.21     8.00     0.12  300.47   0.16   0.01

 

 

man iostat:

-d     The -d option is exclusive of the -c option and displays only the device utilization report.

-x     Display extended statistics.  This option is exclusive of the -p and -n, and works with post 2.5 kernels since it needs /proc/diskstats file or a mounted sysfs to get the statistics. This option may also work with older kernels (e.g. 2.4) only if extended statistics are available in /proc/partitions (the kernel needs to be  patched for that).

%util Percentage of CPU time during which I/O requests were issued to the device (bandwidth utilization for the device). Device saturation occurs when this value  is close to 100%.

一秒中有百分之多少的時間用於I/O操作,或者說一秒中有多少時間I/O佇列是非空的。如果%util接近100%,表明I/O請求太多,I/O系統已經滿負荷,磁碟可能存在瓶頸,一般%util大於70%,I/O壓力就比較大,讀取速度有較多的wait。 

參考:linux 檢視磁碟IO狀態操作指南

 

程式碼:

 

複製程式碼

<span style="font-size:14px;">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;

import org.apache.log4j.Logger;

/**
 * 採集磁碟IO使用率
 */
public class IoUsage extends ResourceUsage{

    private static Logger log = Logger.getLogger(IoUsage.class);
    private static IoUsage INSTANCE = new IoUsage();
    
    private IoUsage(){
    
    }
    
    public static IoUsage getInstance(){
        return INSTANCE;
    }
    
    /**
     * @Purpose:採集磁碟IO使用率
     * @param args
     * @return float,磁碟IO使用率,小於1
     */
    @Override
    public float get() {
        log.info("開始收集磁碟IO使用率");
        float ioUsage = 0.0f;
        Process pro = null;
        Runtime r = Runtime.getRuntime();
        try {
            String command = "iostat -d -x";
            pro = r.exec(command);
            BufferedReader in = new BufferedReader(new InputStreamReader(pro.getInputStream()));
            String line = null;
            int count =  0;
            while((line=in.readLine()) != null){        
                if(++count >= 4){
//                    log.info(line);
                    String[] temp = line.split("\\s+");
                    if(temp.length > 1){
                        float util =  Float.parseFloat(temp[temp.length-1]);
                        ioUsage = (ioUsage>util)?ioUsage:util;
                    }
                }
            }
            if(ioUsage > 0){
                log.info("本節點磁碟IO使用率為: " + ioUsage);    
                ioUsage /= 100; 
            }            
            in.close();
            pro.destroy();
        } catch (IOException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            log.error("IoUsage發生InstantiationException. " + e.getMessage());
            log.error(sw.toString());
        }    
        return ioUsage;
    }

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        while(true){
            System.out.println(IoUsage.getInstance().get());
            Thread.sleep(5000);
        }
    }

}</span>

複製程式碼

 

 

四、網路頻寬

 

從/proc檔案系統獲取網路使用情況:   cat /proc/net/dev

 

[[email protected] LoadBalanceAlg]# cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo:1402131426 15109136    0    0    0     0          0         0 1402131426 15109136    0    0    0     0       0          0
  eth0:4546168400 42535979    0    0    0     0          0        44 5610190492 8943999    0    0    0     0       0          0
  eth1:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
  eth3:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
__tmp945063435:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
 bond0:4546168400 42535979    0    0    0     0          0        44 5610190492 8943999    0    0    0     0       0          0

統計一段時間內Receive和Tramsmit的bytes數的變化,即可獲得網口傳輸速率,再除以網口的頻寬就得到頻寬的使用率

 

程式碼:

複製程式碼

<span style="font-size:14px;">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;

import org.apache.log4j.Logger;

/**
 * 採集網路頻寬使用率
 */
public class NetUsage extends ResourceUsage {

    private static Logger log = Logger.getLogger(NetUsage.class);
    private static NetUsage INSTANCE = new NetUsage();
    private final static float TotalBandwidth = 1000;    //網口頻寬,Mbps
    
    private NetUsage(){
    
    }
    
    public static NetUsage getInstance(){
        return INSTANCE;
    }
    
    /**
     * @Purpose:採集網路頻寬使用率
     * @param args
     * @return float,網路頻寬使用率,小於1
     */
    @Override
    public float get() {
        log.info("開始收集網路頻寬使用率");
        float netUsage = 0.0f;
        Process pro1,pro2;
        Runtime r = Runtime.getRuntime();
        try {
            String command = "cat /proc/net/dev";
            //第一次採集流量資料
            long startTime = System.currentTimeMillis();
            pro1 = r.exec(command);
            BufferedReader in1 = new BufferedReader(new InputStreamReader(pro1.getInputStream()));
            String line = null;
            long inSize1 = 0, outSize1 = 0;
            while((line=in1.readLine()) != null){    
                line = line.trim();
                if(line.startsWith("eth0")){
                    log.info(line);
                    String[] temp = line.split("\\s+"); 
                    inSize1 = Long.parseLong(temp[0].substring(5));    //Receive bytes,單位為Byte
                    outSize1 = Long.parseLong(temp[8]);                //Transmit bytes,單位為Byte
                    break;
                }                
            }    
            in1.close();
            pro1.destroy();
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                StringWriter sw = new StringWriter();
                e.printStackTrace(new PrintWriter(sw));
                log.error("NetUsage休眠時發生InterruptedException. " + e.getMessage());
                log.error(sw.toString());
            }
            //第二次採集流量資料
            long endTime = System.currentTimeMillis();
            pro2 = r.exec(command);
            BufferedReader in2 = new BufferedReader(new InputStreamReader(pro2.getInputStream()));
            long inSize2 = 0 ,outSize2 = 0;
            while((line=in2.readLine()) != null){    
                line = line.trim();
                if(line.startsWith("eth0")){
                    log.info(line);
                    String[] temp = line.split("\\s+"); 
                    inSize2 = Long.parseLong(temp[0].substring(5));
                    outSize2 = Long.parseLong(temp[8]);
                    break;
                }                
            }
            if(inSize1 != 0 && outSize1 !=0 && inSize2 != 0 && outSize2 !=0){
                float interval = (float)(endTime - startTime)/1000;
                //網口傳輸速度,單位為bps
                float curRate = (float)(inSize2 - inSize1 + outSize2 - outSize1)*8/(1000000*interval);
                netUsage = curRate/TotalBandwidth;
                log.info("本節點網口速度為: " + curRate + "Mbps");
                log.info("本節點網路頻寬使用率為: " + netUsage);
            }                
            in2.close();
            pro2.destroy();
        } catch (IOException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            log.error("NetUsage發生InstantiationException. " + e.getMessage());
            log.error(sw.toString());
        }    
        return netUsage;
    }

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        while(true){
            System.out.println(NetUsage.getInstance().get());
            Thread.sleep(5000);
        }
    }
}</span>