รับข้อมูลระบบระดับ OS


232

ขณะนี้ฉันกำลังสร้างแอป Java ที่สามารถลงเอยด้วยการใช้งานบนแพลตฟอร์มที่แตกต่างกัน แต่ส่วนใหญ่แตกต่างจาก Solaris, Linux และ Windows

มีใครสามารถแยกข้อมูลเช่นพื้นที่ดิสก์ปัจจุบันที่ใช้การใช้งาน CPU และหน่วยความจำที่ใช้ในระบบปฏิบัติการพื้นฐานได้สำเร็จหรือไม่ แอป Java กำลังทำงานอะไรอยู่

โดยเฉพาะอย่างยิ่งฉันต้องการรับข้อมูลนี้โดยไม่ใช้ JNI


3
สำหรับหน่วยความจำที่ว่างให้ดูstackoverflow.com/a/18366283/231397 ( Runtime.getRuntime().freeMemory()ตามที่แนะนำในคำตอบที่ยอมรับไม่ได้ให้หน่วยความจำฟรีกับคุณ
Christian Fries

คำตอบ:


206

คุณสามารถรับข้อมูลหน่วยความจำที่ จำกัด จากคลาสรันไทม์ มันไม่ได้เป็นอย่างที่คุณกำลังมองหา แต่ฉันคิดว่าฉันจะให้มันเพื่อความสมบูรณ์ นี่คือตัวอย่างเล็ก ๆ แก้ไข: คุณยังสามารถรับข้อมูลการใช้ดิสก์ได้จากคลาส java.io.File สิ่งที่ใช้พื้นที่ดิสก์ต้องใช้ Java 1.6 หรือสูงกว่า

public class Main {
  public static void main(String[] args) {
    /* Total number of processors or cores available to the JVM */
    System.out.println("Available processors (cores): " + 
        Runtime.getRuntime().availableProcessors());

    /* Total amount of free memory available to the JVM */
    System.out.println("Free memory (bytes): " + 
        Runtime.getRuntime().freeMemory());

    /* This will return Long.MAX_VALUE if there is no preset limit */
    long maxMemory = Runtime.getRuntime().maxMemory();
    /* Maximum amount of memory the JVM will attempt to use */
    System.out.println("Maximum memory (bytes): " + 
        (maxMemory == Long.MAX_VALUE ? "no limit" : maxMemory));

    /* Total memory currently available to the JVM */
    System.out.println("Total memory available to JVM (bytes): " + 
        Runtime.getRuntime().totalMemory());

    /* Get a list of all filesystem roots on this system */
    File[] roots = File.listRoots();

    /* For each filesystem root, print some info */
    for (File root : roots) {
      System.out.println("File system root: " + root.getAbsolutePath());
      System.out.println("Total space (bytes): " + root.getTotalSpace());
      System.out.println("Free space (bytes): " + root.getFreeSpace());
      System.out.println("Usable space (bytes): " + root.getUsableSpace());
    }
  }
}

7
ฉันคิดว่า "หน่วยความจำทั้งหมดที่ JVM ใช้อยู่ในปัจจุบัน" ค่อนข้างสับสนเล็กน้อย Javadocกล่าวว่าผลตอบแทนที่ฟังก์ชั่น "จำนวนของหน่วยความจำที่มีอยู่ในปัจจุบันสำหรับวัตถุในปัจจุบันและอนาคตวัดในไบต์." ฟังดูเหมือนหน่วยความจำเหลือและไม่ได้ใช้งาน
Dirk

@Dirk: ฉันได้อัปเดตข้อความเพื่อแสดงความคิดเห็นของคุณ ขอบคุณ!
William Brendel

@ LeonardoGaldioli: ฉันไม่รู้ลักษณะการทำงานของคลาสและวิธีการเหล่านี้ แต่ฉันจะไม่แปลกใจถ้าพวกเขาไม่ได้เพิ่มประสิทธิภาพความเร็ว คำตอบอื่น ๆ อธิบายวิธีรวบรวมข้อมูลบางอย่างโดยใช้ JMX ซึ่งอาจเร็วกว่า
William Brendel

15
สิ่งนี้ไม่สามารถตอบคำถามได้อย่างถูกต้อง ข้อมูลทั้งหมดนั้นเข้าสู่ JVM และไม่ใช่ไปยังระบบปฏิบัติการ ...
อัลวาโร

ฉันรู้ว่าหัวข้อนี้ค่อนข้างล้าสมัย แต่: หากคุณต้องการปริมาณของ cpu cores จริงๆอย่าใช้วิธีนี้ ฉันมีซีพียูแบบดูอัลคอร์ที่มีสองเธรดสำหรับแต่ละคอร์ JVM ไม่ได้ส่งคืนแกนฮาร์ดแวร์ แต่เป็นแกนซอฟต์แวร์ / เธรด
F_Schmidt

95

java.lang.managementแพคเกจไม่ให้ข้อมูลเป็นจำนวนมากทั้งมากกว่า Runtime - ตัวอย่างเช่นมันจะทำให้คุณหน่วยความจำกอง ( ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()) แยกออกจากหน่วยความจำไม่กอง ( ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage())

นอกจากนี้คุณยังจะได้รับการใช้งาน CPU กระบวนการ (โดยไม่ต้องเขียนรหัส JNI ของคุณเอง) แต่คุณต้องโยนไปjava.lang.management.OperatingSystemMXBean com.sun.management.OperatingSystemMXBeanสิ่งนี้ใช้ได้กับ Windows และ Linux ฉันยังไม่ได้ทดสอบที่อื่น

ตัวอย่างเช่น ... เรียกเมธอด getCpuUsage () บ่อยขึ้นเพื่อให้การอ่านแม่นยำยิ่งขึ้น

public class PerformanceMonitor { 
    private int  availableProcessors = getOperatingSystemMXBean().getAvailableProcessors();
    private long lastSystemTime      = 0;
    private long lastProcessCpuTime  = 0;

    public synchronized double getCpuUsage()
    {
        if ( lastSystemTime == 0 )
        {
            baselineCounters();
            return;
        }

        long systemTime     = System.nanoTime();
        long processCpuTime = 0;

        if ( getOperatingSystemMXBean() instanceof OperatingSystemMXBean )
        {
            processCpuTime = ( (OperatingSystemMXBean) getOperatingSystemMXBean() ).getProcessCpuTime();
        }

        double cpuUsage = (double) ( processCpuTime - lastProcessCpuTime ) / ( systemTime - lastSystemTime );

        lastSystemTime     = systemTime;
        lastProcessCpuTime = processCpuTime;

        return cpuUsage / availableProcessors;
    }

    private void baselineCounters()
    {
        lastSystemTime = System.nanoTime();

        if ( getOperatingSystemMXBean() instanceof OperatingSystemMXBean )
        {
            lastProcessCpuTime = ( (OperatingSystemMXBean) getOperatingSystemMXBean() ).getProcessCpuTime();
        }
    }
}

10
ที่จะได้ไปรวบรวมแทนที่โยนOperatingSystemMXBeanไปcom.sun.management.OperatingSystemMXBeanและคำนำทุกกรณีด้วยgetOperatingSystemMXBean() ManagementFactory.คุณต้องนำเข้าทุกชั้นอย่างเหมาะสม
tmarthal

2
ฉันได้รับการใช้งาน cpu เป็น 0 ทุกอย่าง ฉันเปลี่ยนสูตรการใช้ cpu เป็น cpuUsage = processCpuTime / systemTime ฉันได้รับค่าสำหรับการใช้ซีพียูซึ่งฉันไม่เข้าใจ
ราชา

ไม่1.0เป็นผลจากgetCpuUsageค่าเฉลี่ยว่าระบบที่ใช้ทั้งหมดของavailableProcessorsที่ 100%?
user454322

2
ฉันได้ 0 เป็นเสมอ @Raj กล่าวว่า ... คุณสามารถยกตัวอย่างวิธีใช้รหัสได้หรือไม่
dm76

1
ลอง((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
แอนโทนี่ O.

43

ผมคิดว่าวิธีที่ดีที่สุดออกมีที่จะใช้API Sigar โดย Hyperic มันใช้งานได้กับระบบปฏิบัติการส่วนใหญ่ (ใกล้สิ่งใด ๆ ที่ทันสมัย) และใช้งานได้ง่ายมาก นักพัฒนามีการตอบสนองมากในฟอรั่มและรายชื่อผู้รับจดหมาย ฉันยังชอบว่ามันGPL2 Apache ได้รับใบอนุญาต พวกเขาให้ตัวอย่างมากมายใน Java เช่นกัน!

SIGAR == ข้อมูลระบบการรวบรวมและการรายงานเครื่องมือ


2
@Yohan - อย่าขี้เกียจ! คุณสามารถค้นหาได้โดยการอ่านหน้าเว็บที่เชื่อมโยง (และขึ้นอยู่กับสิ่งที่คุณหมายถึงโดย "แพลตฟอร์มอิสระ")
สตีเฟ่นซี

2
@StephenC: Sigar ใช้ไฟล์. dll ซึ่งขึ้นอยู่กับแพลตฟอร์ม API ระดับที่สูงกว่าอาจอยู่ใน Java มันเป็นเรื่องที่แตกต่าง
น้ำมะนาว

1
@Artificial_Intelligence ใช่ แต่ให้บริการห้องสมุด (เขียนเป็น c) สำหรับแพลตฟอร์มยอดนิยม มันไม่ขึ้นอยู่กับแพลตฟอร์มมากกว่าตัว jvm เอง Java API ระดับที่สูงขึ้นควรสอดคล้องกับทุกแพลตฟอร์ม
Jeshurun

8
Sigar ไม่ได้รับการปรับปรุงตั้งแต่ปี 2010 และดูเหมือนว่าจะมีข้อผิดพลาดในระบบ 64 บิต: stackoverflow.com/questions/23405832/…
Alvaro

1
และ SIGAR ทำให้ JVM หยุดทำงานด้วยเช่นกัน (แต่ไม่ต่อเนื่อง) แต่ฉันมั่นใจว่าคุณจะไม่รับความเสี่ยงนี้ในการผลิต
AKS

25

มีโปรเจ็กต์ Java ที่ใช้ JNA (ไม่มีไลบรารี่ในการติดตั้ง) และอยู่ในระหว่างการพัฒนา ปัจจุบันรองรับ Linux, OSX, Windows, Solaris และ FreeBSD และให้ RAM, CPU, แบตเตอรี่และข้อมูลระบบไฟล์


อาจไม่มีห้องสมุดท้องถิ่นที่ทำให้เข้าใจผิด โครงการใช้ไลบรารีเนทีฟแม้ว่าจะไม่ได้เขียนอะไรเลยและคุณไม่จำเป็นต้องติดตั้งใด ๆ
Stephen C

1
คุณถูก. JNA ใช้ libffi ที่มีส่วนประกอบพื้นฐาน แต่สำหรับทุกวัตถุประสงค์ดูเหมือนว่าไม่มีไลบรารี่ดั้งเดิม (แน่นอนไม่มีให้ติดตั้ง)
เดซิเบล

@StephenC แม้ว่าสิ่งที่คุณพูดนั้นถูกต้อง แต่ก็ทำให้เข้าใจผิดเพราะมันเหมือนกันสำหรับ rt.jar ซึ่งยังเรียกใช้วิธีการดั้งเดิม เหตุผลเดียวที่ผู้คนสนใจเกี่ยวกับวิธีการดั้งเดิมคือต้องรวบรวมและ / หรือติดตั้งซึ่งมักจะเป็นงานที่ไม่สำคัญ เนื่องจาก libffi มีการนำไปใช้อย่างกว้างขวางนำไปใช้และติดตั้งจึงช่วยลดปัญหา ดังนั้นในทางเทคนิคคุณถูกต้อง แต่ในทางปฏิบัติมันไม่สำคัญ
rbp

@rbp - มีอีกเหตุผลหนึ่งที่ทำให้คนที่มีประสบการณ์การพัฒนา Java ต้องการหลีกเลี่ยงห้องสมุดท้องถิ่น ไลบรารีดั้งเดิมที่มีข้อบกพร่อง (รวมถึงปัญหาด้านความปลอดภัยของเธรดหรือปัญหาเกี่ยวกับการจัดการหน่วยความจำ) มีแนวโน้มที่จะทำให้โฮสต์ JVM ไม่เสถียร นี่ไม่ใช่ปัญหา"มันไม่สำคัญ" ....
สตีเฟ่นซี

@StephenC มีการเขียนเซิร์ฟเวอร์แอปพลิเคชันเว็บทำให้ฉันมีประสบการณ์เพียงพอหรือไม่
rbp

13

สำหรับ windows ฉันไปทางนี้

    com.sun.management.OperatingSystemMXBean os = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();

    long physicalMemorySize = os.getTotalPhysicalMemorySize();
    long freePhysicalMemory = os.getFreePhysicalMemorySize();
    long freeSwapSize = os.getFreeSwapSpaceSize();
    long commitedVirtualMemorySize = os.getCommittedVirtualMemorySize();

นี่คือลิงค์พร้อมรายละเอียด


11

คุณสามารถรับข้อมูลระดับระบบโดยใช้System.getenv()ผ่านชื่อตัวแปรสภาพแวดล้อมที่เกี่ยวข้องเป็นพารามิเตอร์ ตัวอย่างเช่นบน Windows:

System.getenv("PROCESSOR_IDENTIFIER")
System.getenv("PROCESSOR_ARCHITECTURE")
System.getenv("PROCESSOR_ARCHITEW6432")
System.getenv("NUMBER_OF_PROCESSORS")

สำหรับระบบปฏิบัติการอื่นการมีอยู่ / ไม่มีและชื่อของตัวแปรสภาพแวดล้อมที่เกี่ยวข้องจะแตกต่างกัน


1
สิ่งเหล่านี้ขึ้นอยู่กับแพลตฟอร์มเนื่องจากชื่อตัวแปรแตกต่างกันระหว่างระบบ บทความ Oracle เกี่ยวกับตัวแปรสภาพแวดล้อมบอกว่า ฉันกำลังหาวิธีที่จะได้รับระบบที่เป็นอิสระ
น้ำมะนาว

ภายใต้ Linux (Ubuntu 17.10) มีข้อมูลที่น่าสนใจไม่มากเกี่ยวกับโปรเซสเซอร์ในสภาพแวดล้อม
pveentjer

8

เพิ่มการพึ่งพา OSHI ผ่าน maven:

<dependency>
    <groupId>com.github.dblock</groupId>
    <artifactId>oshi-core</artifactId>
    <version>2.2</version>
</dependency>

รับความจุแบตเตอรี่เหลือเปอร์เซ็นต์:

SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
for (PowerSource pSource : hal.getPowerSources()) {
    System.out.println(String.format("%n %s @ %.1f%%", pSource.getName(), pSource.getRemainingCapacity() * 100d));
}

OSHI มีข้อมูลส่วนใหญ่ที่อธิบายไว้ในความคิดเห็นอื่น ๆ มันใช้ JNA เพื่อรับมันผ่านการโทรตามระบบปฏิบัติการเมื่อเป็นไปได้
Daniel Widdis

6

ดูที่ APIs ที่มีอยู่ในแพ็คเกจjava.lang.management ตัวอย่างเช่น:

  • OperatingSystemMXBean.getSystemLoadAverage()
  • ThreadMXBean.getCurrentThreadCpuTime()
  • ThreadMXBean.getCurrentThreadUserTime()

มีสิ่งอื่น ๆ ที่เป็นประโยชน์มากมายในนั้นเช่นกัน


2
OperatingSystemMXBean.getSystemLoadAverage () ไม่ได้ดำเนินการในหน้าต่างเพราะ "แพงเกินไป"
MikeNereson

1
ThreadMXBean.getCurrentThreadCpuTime () จะคืนค่าระยะเวลาที่เธรดนั้นรันอยู่เท่านั้น ไม่ใช่เปอร์เซ็นต์การใช้ cpu
MikeNereson

5

โดยปกติแล้วหากต้องการข้อมูลระบบปฏิบัติการระดับต่ำคุณสามารถเรียกคำสั่งเฉพาะระบบปฏิบัติการซึ่งให้ข้อมูลที่คุณต้องการด้วย Runtime.exec () หรืออ่านไฟล์เช่น / proc / * ใน Linux


5

การใช้ซีพียูไม่ได้ตรงไปตรงมา - java.lang.management ผ่าน com.sun.management.OperatingSystemMXBean.getProcessCpuTime เข้ามาใกล้ (ดูรหัสที่ยอดเยี่ยมของแพทริคด้านบน) แต่โปรดทราบว่ามันให้เวลาเข้าถึง CPU ที่ใช้ในกระบวนการของคุณเท่านั้น มันจะไม่บอกคุณเกี่ยวกับเวลา CPU ที่ใช้ในกระบวนการอื่น ๆ หรือแม้แต่เวลา CPU ที่ใช้ในการทำกิจกรรมของระบบที่เกี่ยวข้องกับกระบวนการของคุณ

เช่นฉันมีกระบวนการ java ที่ใช้เครือข่ายมาก - เป็นสิ่งเดียวที่ทำงานและ CPU อยู่ที่ 99% แต่มีเพียง 55% เท่านั้นที่รายงานว่าเป็น "ซีพียูโปรเซสเซอร์"

อย่าให้ฉันเริ่มต้นด้วย "load average" เพราะอยู่ติดกับไร้ประโยชน์แม้จะเป็นรายการที่เกี่ยวข้องกับ cpu เพียงรายการเดียวใน MX bean ถ้าเพียงดวงอาทิตย์ในภูมิปัญญาของพวกเขาเป็นครั้งคราวสัมผัสบางสิ่งบางอย่างเช่น "getTotalCpuTime" ...

สำหรับการตรวจสอบ CPU อย่างจริงจัง SIGAR ที่กล่าวถึงโดย Matt ดูเหมือนจะเป็นทางออกที่ดีที่สุด


4

ในวันที่Windowsคุณสามารถเรียกใช้systeminfoคำสั่งและดึงเอาท์พุทของมันตัวอย่างเช่นด้วยรหัสต่อไปนี้:

private static class WindowsSystemInformation
{
    static String get() throws IOException
    {
        Runtime runtime = Runtime.getRuntime();
        Process process = runtime.exec("systeminfo");
        BufferedReader systemInformationReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

        StringBuilder stringBuilder = new StringBuilder();
        String line;

        while ((line = systemInformationReader.readLine()) != null)
        {
            stringBuilder.append(line);
            stringBuilder.append(System.lineSeparator());
        }

        return stringBuilder.toString().trim();
    }
}

3

หากคุณใช้ Jrockit VM นี่คือวิธีอื่นในการรับการใช้งาน CPU CPU รันไทม์บีนยังสามารถมอบซีพียูให้คุณต่อโปรเซสเซอร์ ฉันใช้สิ่งนี้กับ Red Hat Linux เท่านั้นเพื่อสังเกตการณ์ประสิทธิภาพของ Tomcat คุณต้องเปิดใช้งาน JMX remote ใน catalina.sh เพื่อให้ทำงานได้

JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://my.tomcat.host:8080/jmxrmi");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);     
MBeanServerConnection conn = jmxc.getMBeanServerConnection();       
ObjectName name = new ObjectName("oracle.jrockit.management:type=Runtime");
Double jvmCpuLoad =(Double)conn.getAttribute(name, "VMGeneratedCPULoad");

3

มันยังอยู่ระหว่างการพัฒนา แต่คุณสามารถใช้jHardwareได้แล้ว

มันเป็นห้องสมุดง่าย ๆ ที่จะทิ้งข้อมูลระบบโดยใช้ Java มันทำงานได้ทั้งใน Linux และ Windows

ProcessorInfo info = HardwareInfo.getProcessorInfo();
//Get named info
System.out.println("Cache size: " + info.getCacheSize());        
System.out.println("Family: " + info.getFamily());
System.out.println("Speed (Mhz): " + info.getMhz());
//[...]

ดี แต่ใช้รุ่น Guava และ JNA ที่ขัดแย้งกับความต้องการของฉัน (เช่นดูGLASSFISH-21367 )
lu_ko

สวัสดี JNA ได้รับการแนะนำใน jHardware รุ่น 0.8 มันใช้สำหรับข้อมูลอุณหภูมิและเซ็นเซอร์เท่านั้น หากคุณไม่ต้องการข้อมูลนั้นคุณสามารถใช้เวอร์ชั่น 0.7 ได้ สิ่งเดียวกันสำหรับฝรั่ง ในกรณีนี้คุณจะต้องใช้เวอร์ชั่น 0.6.3
profesor_falken

2

วิธีง่ายๆที่สามารถใช้เพื่อรับข้อมูลระดับ OS และฉันทดสอบใน Mac ของฉันซึ่งทำงานได้ดี:

 OperatingSystemMXBean osBean =
        (OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
    return osBean.getProcessCpuLoad();

คุณสามารถค้นหาตัวชี้วัดที่เกี่ยวข้องของระบบปฏิบัติการได้ที่นี่


1

สวัสดีคุณสามารถทำได้ด้วยการรวม java / com ด้วยการเข้าถึงคุณสมบัติ WMI คุณจะได้รับข้อมูลทั้งหมด


0

ในการรับค่าเฉลี่ยโหลดระบบเป็น 1 นาที, 5 นาทีและ 15 นาทีภายในโค้ดจาวาคุณสามารถทำได้โดยดำเนินการคำสั่งcat /proc/loadavgโดยใช้และตีความมันดังต่อไปนี้:

    Runtime runtime = Runtime.getRuntime();

    BufferedReader br = new BufferedReader(
        new InputStreamReader(runtime.exec("cat /proc/loadavg").getInputStream()));

    String avgLine = br.readLine();
    System.out.println(avgLine);
    List<String> avgLineList = Arrays.asList(avgLine.split("\\s+"));
    System.out.println(avgLineList);
    System.out.println("Average load 1 minute : " + avgLineList.get(0));
    System.out.println("Average load 5 minutes : " + avgLineList.get(1));
    System.out.println("Average load 15 minutes : " + avgLineList.get(2));

และเพื่อรับหน่วยความจำระบบกายภาพโดยการดำเนินการคำสั่งfree -mแล้วตีความมันดังต่อไปนี้:

Runtime runtime = Runtime.getRuntime();

BufferedReader br = new BufferedReader(
    new InputStreamReader(runtime.exec("free -m").getInputStream()));

String line;
String memLine = "";
int index = 0;
while ((line = br.readLine()) != null) {
  if (index == 1) {
    memLine = line;
  }
  index++;
}
//                  total        used        free      shared  buff/cache   available
//    Mem:          15933        3153        9683         310        3097       12148
//    Swap:          3814           0        3814

List<String> memInfoList = Arrays.asList(memLine.split("\\s+"));
int totalSystemMemory = Integer.parseInt(memInfoList.get(1));
int totalSystemUsedMemory = Integer.parseInt(memInfoList.get(2));
int totalSystemFreeMemory = Integer.parseInt(memInfoList.get(3));

System.out.println("Total system memory in mb: " + totalSystemMemory);
System.out.println("Total system used memory in mb: " + totalSystemUsedMemory);
System.out.println("Total system free memory in mb: "   + totalSystemFreeMemory);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.