首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 獲取伺服器系統資訊:基於 Sigar 庫的完整實作

     編輯:Java 相關知識

前言

Java 標準庫對作業系統底層資訊(CPU、記憶體、磁碟、網路)支援有限。Hyperic Sigar 是一個成熟的跨平台系統資訊庫,透過 JNI 呼叫原生 API,提供統一介面獲取硬體與 OS 指標。本文整理完整實作範例,涵蓋 CPU、記憶體、檔案系統、網路介面、作業系統資訊等核心場景。

環境準備

  1. 下載 sigar.jar 並加入專案類路徑。
  2. 根據部署環境放置原生庫:
    • Windows x64: sigar-amd64-winnt.dll
    • Windows x86: sigar-x86-winnt.dll
    • Linux x64: libsigar-amd64-linux.so
    • Linux x86: libsigar-x86-linux.so
    原生庫需放在 java.library.path 指定目錄或系統 PATH 中。

核心工具類:SysInfo

import org.hyperic.sigar.*;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class SysInfo {
    private static final Sigar sigar = new Sigar();
    
    // ========== CPU 資訊 ==========
    public static int getCpuCount() throws SigarException {
        return sigar.getCpuInfoList().length;
    }
    
    public static void printCpuDetails() throws SigarException {
        CpuInfo[] infos = sigar.getCpuInfoList();
        for (int i = 0; i < infos.length; i++) {
            CpuInfo info = infos[i];
            System.out.printf("CPU[%d]: MHz=%d, Vendor=%s, Model=%s, Cache=%d KB%n",
                i, info.getMhz(), info.getVendor(), info.getModel(), info.getCacheSize());
        }
    }
    
    public static void printCpuUsage() throws SigarException {
        CpuPerc[] cpuList = sigar.getCpuPercList();
        for (int i = 0; i < cpuList.length; i++) {
            CpuPerc cpu = cpuList[i];
            System.out.printf("CPU[%d] User=%.1f%% Sys=%.1f%% Idle=%.1f%% Total=%.1f%%%n",
                i,
                cpu.getUser() * 100, cpu.getSys() * 100,
                cpu.getIdle() * 100, cpu.getCombined() * 100);
        }
    }
    
    // ========== 記憶體資訊 ==========
    public static void printMemoryInfo() throws SigarException {
        Mem mem = sigar.getMem();
        Swap swap = sigar.getSwap();
        
        System.out.println("=== 物理記憶體 ===");
        System.out.printf("Total: %,d MB%n", mem.getTotal() / 1024 / 1024);
        System.out.printf("Used:  %,d MB%n", mem.getUsed() / 1024 / 1024);
        System.out.printf("Free:  %,d MB%n", mem.getFree() / 1024 / 1024);
        
        System.out.println("=== Swap 交換區 ===");
        System.out.printf("Total: %,d MB%n", swap.getTotal() / 1024 / 1024);
        System.out.printf("Used:  %,d MB%n", swap.getUsed() / 1024 / 1024);
        System.out.printf("Free:  %,d MB%n", swap.getFree() / 1024 / 1024);
    }
    
    // ========== 作業系統資訊 ==========
    public static String getHostName() {
        try {
            return InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            try { return sigar.getNetInfo().getHostName(); }
            catch (SigarException ignored) { return "localhost.unknown"; }
        }
    }
    
    public static void printOsInfo() {
        OperatingSystem os = OperatingSystem.getInstance();
        System.out.println("Arch: " + os.getArch());
        System.out.println("Description: " + os.getDescription());
        System.out.println("Name: " + os.getName());
        System.out.println("Version: " + os.getVersion());
        System.out.println("Vendor: " + os.getVendor());
    }
    
    // ========== 檔案系統(磁碟) ==========
    public static void printFileSystemInfo() throws SigarException {
        FileSystem[] fsList = sigar.getFileSystemList();
        for (int i = 0; i < fsList.length; i++) {
            FileSystem fs = fsList[i];
            FileSystemUsage usage = sigar.getFileSystemUsage(fs.getDirName());
            
            System.out.printf("%n=== Partition %d: %s (%s) ===%n", 
                i, fs.getDevName(), fs.getDirName());
            System.out.printf("Type: %s | SysType: %s | Flags: %s%n",
                fs.getTypeName(), fs.getSysTypeName(), fs.getFlags());
            
            if (fs.getType() == FileSystem.TYPE_LOCAL_DISK) {
                System.out.printf("Total: %,d GB | Free: %,d GB | Used: %,d GB | Usage: %.1f%%%n",
                    usage.getTotal() / 1024 / 1024 / 1024,
                    usage.getFree() / 1024 / 1024 / 1024,
                    usage.getUsed() / 1024 / 1024 / 1024,
                    usage.getUsePercent() * 100);
                System.out.printf("Reads: %,d | Writes: %,d%n",
                    usage.getDiskReads(), usage.getDiskWrites());
            }
        }
    }
    
    // ========== 網路資訊 ==========
    public static String getDefaultIp() {
        try {
            String ip = InetAddress.getLocalHost().getHostAddress();
            if (!NetFlags.LOOPBACK_ADDRESS.equals(ip)) return ip;
        } catch (UnknownHostException ignored) {}
        try { return sigar.getNetInterfaceConfig().getAddress(); }
        catch (SigarException e) { return NetFlags.LOOPBACK_ADDRESS; }
    }
    
    public static String getMacAddress() {
        try {
            String[] ifaces = sigar.getNetInterfaceList();
            for (String iface : ifaces) {
                NetInterfaceConfig cfg = sigar.getNetInterfaceConfig(iface);
                if (NetFlags.LOOPBACK_ADDRESS.equals(cfg.getAddress()) ||
                    (cfg.getFlags() & NetFlags.IFF_LOOPBACK) != 0 ||
                    NetFlags.NULL_HWADDR.equals(cfg.getHwaddr())) {
                    continue;
                }
                return cfg.getHwaddr();
            }
        } catch (SigarException ignored) {}
        return null;
    }
    
    public static void printNetworkStats() throws SigarException {
        String[] ifNames = sigar.getNetInterfaceList();
        for (String name : ifNames) {
            NetInterfaceConfig cfg = sigar.getNetInterfaceConfig(name);
            if ((cfg.getFlags() & 1L) == 0) continue; // IFF_UP
            
            NetInterfaceStat stat = sigar.getNetInterfaceStat(name);
            System.out.printf("%nInterface: %s (%s)%n", name, cfg.getAddress());
            System.out.printf("  RX: %,d packets, %,d bytes, %,d errors, %,d dropped%n",
                stat.getRxPackets(), stat.getRxBytes(), stat.getRxErrors(), stat.getRxDropped());
            System.out.printf("  TX: %,d packets, %,d bytes, %,d errors, %,d dropped%n",
                stat.getTxPackets(), stat.getTxBytes(), stat.getTxErrors(), stat.getTxDropped());
        }
    }
    
    // ========== 登入用戶 ==========
    public static void printLoggedInUsers() throws SigarException {
        Who[] users = sigar.getWhoList();
        for (int i = 0; i < users.length; i++) {
            Who u = users[i];
            System.out.printf("User[%d]: %s @ %s on %s since %d%n",
                i, u.getUser(), u.getHost(), u.getDevice(), u.getTime());
        }
    }
    
    public static void main(String[] args) {
        try {
            printCpuDetails();
            printCpuUsage();
            printMemoryInfo();
            printOsInfo();
            printFileSystemInfo();
            System.out.println("Host: " + getHostName());
            System.out.println("IP: " + getDefaultIp());
            System.out.println("MAC: " + getMacAddress());
            printNetworkStats();
            printLoggedInUsers();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try { sigar.close(); } catch (Exception ignored) {}
        }
    }
}

關鍵類別與方法對照表

功能Sigar 類別核心方法
CPU 邏輯核心數CpuInfogetCpuInfoList().length
CPU 使用率CpuPercgetCpuPercList() → getUser()/getSys()/getIdle()/getCombined()
物理記憶體MemgetMem() → getTotal()/getUsed()/getFree()
Swap 交換區SwapgetSwap() → getTotal()/getUsed()/getFree()
檔案系統列表FileSystemgetFileSystemList()
分區使用率FileSystemUsagegetFileSystemUsage(dir) → getTotal()/getFree()/getUsePercent()
網路介面配置NetInterfaceConfiggetNetInterfaceConfig(name) → getAddress()/getNetmask()/getHwaddr()
網路流量統計NetInterfaceStatgetNetInterfaceStat(name) → getRxBytes()/getTxBytes()/getRxPackets()/getTxPackets()
登入用戶WhogetWhoList() → getUser()/getHost()/getTime()

常見問題與解決方案

  • UnsatisfiedLinkError:原生庫未找到。確認 sigar-amd64-winnt.dll 或 .so 檔案在 java.library.path 或系統 PATH 中。
  • 權限不足:Linux 下讀取 /proc 或網路統計可能需要 root 權限。
  • 資源洩漏:Sigar 實例實作 AutoCloseable,使用後務必呼叫 close() 釋放原生資源。
  • 多網卡 MAC 選擇:範例回傳第一張非回環、非虛擬介面的 MAC;實際部署可根據介面名稱或 IP 段過濾。

替代方案對比

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案優點缺點適用場景
Sigar跨平台、指標豐富、成熟穩定需原生庫、專案已停止維護生產環境監控、老專案維護
oshi (GitHub)純 Java、無原生依賴、活躍維護部分指標依賴平台命令解析新專案、容器化部署
Java 9+ ProcessHandle標準 API、無依賴僅限當前 JVM 進程資訊應用自我監控
JMX / MXBean標準、遠程監控系統級指標有限JVM 內部監控