Nhận thông tin hệ thống cấp hệ điều hành


232

Tôi hiện đang xây dựng một ứng dụng Java có thể chạy trên nhiều nền tảng khác nhau, nhưng chủ yếu là các biến thể của Solaris, Linux và Windows.

Có ai có thể trích xuất thành công thông tin như không gian đĩa hiện tại được sử dụng, sử dụng CPU và bộ nhớ được sử dụng trong HĐH cơ bản không? Điều gì về chính những gì ứng dụng Java đang tiêu thụ?

Tốt nhất là tôi muốn nhận thông tin này mà không cần sử dụng JNI.


3
Đối với bộ nhớ trống, hãy xem stackoverflow.com/a/18366283/231397 ( Runtime.getRuntime().freeMemory()như được đề xuất trong câu trả lời được chấp nhận KHÔNG cho bạn lượng bộ nhớ trống.
Christian Fries

Câu trả lời:


206

Bạn có thể nhận được một số thông tin bộ nhớ hạn chế từ lớp Runtime. Nó thực sự không chính xác những gì bạn đang tìm kiếm, nhưng tôi nghĩ rằng tôi sẽ cung cấp nó cho mục đích hoàn chỉnh. Đây là một ví dụ nhỏ. Chỉnh sửa: Bạn cũng có thể lấy thông tin sử dụng đĩa từ lớp java.io.File. Các công cụ sử dụng không gian đĩa yêu cầu Java 1.6 trở lên.

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
Tôi nghĩ rằng "Tổng bộ nhớ hiện đang được JVM sử dụng" hơi khó hiểu. Các javadoc nói rằng chức năng thu nhập "tổng dung lượng bộ nhớ hiện có sẵn cho các đối tượng hiện tại và tương lai, được đo bằng byte." Âm thanh giống như bộ nhớ còn lại và không sử dụng.
Dirk

@Dirk: Tôi đã cập nhật từ ngữ để giải quyết bình luận của bạn. Cảm ơn!
William Brendel

@LeonardoGaldioli: Tôi không biết các đặc tính hiệu suất của các lớp và phương thức này, nhưng tôi sẽ không ngạc nhiên nếu chúng không được tối ưu hóa cho tốc độ. Các câu trả lời khác giải thích cách thu thập thông tin nhất định bằng JMX, có thể nhanh hơn.
William Brendel

15
Điều này không trả lời chính xác câu hỏi. Tất cả dữ liệu đó được chuyển sang JVM chứ không phải cho HĐH ...
Alvaro

Tôi biết rằng chủ đề này khá lỗi thời. NHƯNG: Nếu bạn thực sự cần số lượng lõi cpu, thì đừng sử dụng giải pháp này. Tôi có một CPU lõi kép với hai luồng cho mỗi lõi. JVM không trả về các lõi phần cứng, mà là các lõi / luồng phần mềm.
F_Schmidt

95

Các java.lang.management gói không cung cấp cho bạn thông tin nhiều hơn cả so với Runtime - ví dụ nó sẽ cung cấp cho bạn bộ nhớ heap ( ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()) tách rời khỏi bộ nhớ non-đống (ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage() ).

Bạn cũng có thể nhận được quá trình sử dụng CPU (không cần viết mã JNI của riêng bạn), nhưng bạn cần chuyển java.lang.management.OperatingSystemMXBeansangcom.sun.management.OperatingSystemMXBean . Điều này hoạt động trên Windows và Linux, tôi đã không thử nghiệm nó ở nơi khác.

Ví dụ ... gọi phương thức getCpuUsage () thường xuyên hơn để có được kết quả chính xác hơn.

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
Để làm cho nó biên dịch, thay thế cast OperatingSystemMXBeanthành com.sun.management.OperatingSystemMXBeanvà mở đầu tất cả các trường hợp getOperatingSystemMXBean()bằng ManagementFactory.. Bạn cần nhập tất cả các lớp một cách thích hợp.
tmarthal

2
Tôi đang sử dụng cpu là 0 cho mọi thứ. tôi đã thay đổi công thức sử dụng cpu thành cpuUsage = processCpuTime / systemTime. Tôi đang nhận được một giá trị cho việc sử dụng cpu mà tôi không hiểu.
Raj

làm 1,0 kết quả từ getCpuUsagetrung bình mà hệ thống đang sử dụng tất cả của nó availableProcessors ở 100%?
dùng454322

2
Tôi luôn nhận được 0 như @Raj đã nói ... bạn có thể cho một ví dụ về cách sử dụng mã đó không?
dm76

1
Hãy thử((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
Anthony O.

43

Tôi nghĩ rằng phương pháp tốt nhất hiện có là triển khai API SIGAR của Hyperic . Nó hoạt động cho hầu hết các hệ điều hành chính (gần như mọi thứ hiện đại) và rất dễ làm việc. Các nhà phát triển rất phản hồi trên diễn đàn và danh sách gửi thư của họ. Tôi cũng thích rằng đó là GPL2 Apache được cấp phép . Họ cũng cung cấp rất nhiều ví dụ trong Java!

SIGAR == Thông tin hệ thống, công cụ thu thập và báo cáo.


2
@Yohan - Đừng lười biếng! Bạn có thể tìm thấy điều đó bằng cách đọc các trang web được liên kết. (Và nó phụ thuộc vào ý của bạn là "độc lập với nền tảng".)
Stephen C

2
@StephenC: Sigar đang sử dụng các tập tin dll, điều này làm cho nó phụ thuộc vào nền tảng. API cấp cao hơn có thể có trong Java, đó là một câu chuyện khác
Lemon Juice

1
@Art mẫu_Intellect có, nhưng nó cung cấp các thư viện (được viết bằng c) cho hầu hết các nền tảng phổ biến. Nó không phụ thuộc nhiều vào nền tảng hơn bản thân jvm. API Java cấp cao hơn phải nhất quán trên tất cả các nền tảng.
Jeshurun

8
Sigar không được cập nhật từ năm 2010 và dường như có lỗi trên các hệ thống 64 bit: stackoverflow.com/questions/23405832/.
Alvaro

1
Và SIGAR cũng làm cho JVM sụp đổ, (mặc dù không liên tục) nhưng tôi chắc chắn bạn sẽ không gặp rủi ro này trong sản xuất.
AKS

25

Có một dự án Java sử dụng JNA (vì vậy không có thư viện riêng để cài đặt) và đang trong quá trình phát triển. Nó hiện hỗ trợ Linux, OSX, Windows, Solaris và FreeBSD và cung cấp thông tin về hệ thống RAM, CPU, Pin và tệp.


Không có thư viện bản địa có lẽ là sai lệch. Dự án sử dụng các thư viện riêng, ngay cả khi chúng chưa được viết, và dường như bạn không cần phải cài đặt bất kỳ.
Stephen C

1
Bạn đúng. JNA sử dụng libffi có các thành phần gốc. Nhưng đối với tất cả các mục đích, có vẻ như không có thư viện riêng (chắc chắn không có thư viện nào để cài đặt).
dB.

@StephenC mặc dù những gì bạn nói là chính xác, nó gây hiểu nhầm bởi vì nó giống với rt.jar, cũng gọi các phương thức gốc. lý do duy nhất mọi người quan tâm đến các phương thức bản địa là họ phải biên dịch và / hoặc cài đặt chúng, thường là một nhiệm vụ không hề nhỏ. vì libffi được chấp nhận rộng rãi, chuyển và cài đặt, nên nó giảm thiểu những khó khăn. vì vậy, về mặt kỹ thuật bạn đã đúng, nhưng thực tế, nó không thành vấn đề.
rbp

@rbp - Có một lý do khác khiến mọi người tại sao các nhà phát triển Java có kinh nghiệm thích tránh các thư viện nguyên gốc. Một thư viện riêng có lỗi (bao gồm các vấn đề an toàn luồng hoặc vấn đề với quản lý bộ nhớ) có thể gây mất ổn định cho JVM máy chủ. Đây không phải là vấn đề "không thành vấn đề" ....
Stephen C

@StephenC có tác giả máy chủ ứng dụng weblogic làm cho tôi đủ kinh nghiệm ?
rbp

13

Đối với cửa sổ tôi đã đi theo cách này.

    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();

Đây là liên kết với các chi tiết.


11

Bạn có thể nhận được một số thông tin cấp hệ thống bằng cách sử dụng System.getenv(), chuyển tên biến môi trường có liên quan làm tham số. Ví dụ: trên Windows:

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

Đối với các hệ điều hành khác, sự hiện diện / vắng mặt và tên của các biến môi trường liên quan sẽ khác nhau.


1
Đây là phụ thuộc nền tảng vì tên biến là khác nhau giữa các hệ thống. Bài viết của Oracle về các biến môi trường nói lên điều đó. Tôi cũng đang tìm một cách để có được hệ thống độc lập.
Nước chanh

Trong Linux (Ubuntu 17.10) không có nhiều thông tin thú vị liên quan đến bộ xử lý trong môi trường.
pveentjer

8

Thêm phụ thuộc OSHI thông qua maven:

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

Nhận dung lượng pin còn lại theo tỷ lệ phần trăm:

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 có hầu hết các thông tin được mô tả trong các ý kiến ​​khác. Nó sử dụng JNA để có được nó thông qua các cuộc gọi riêng của hệ điều hành khi có thể.
Daniel Widdis

6

Hãy xem các API có sẵn trong gói java.lang.man quản lý . Ví dụ:

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

Có rất nhiều thứ hữu ích khác trong đó.


2
OperationsSystemMXBean.getSystemLoadAlusive () không được triển khai trong windows vì "nó quá đắt"
MikeNereson

1
ThreadMXBean.getCienThreadCpuTime () chỉ trả về thời gian mà chủ đề đó đã chạy. Không phải là tỷ lệ sử dụng cpu.
MikeNereson

5

Thông thường, để có được thông tin hệ điều hành cấp thấp, bạn có thể gọi các lệnh cụ thể của HĐH cung cấp cho bạn thông tin bạn muốn với Runtime.exec () hoặc đọc các tệp như / Proc / * trong Linux.


5

Việc sử dụng CPU không đơn giản - java.lang.man Quản lý thông qua com.sun.man Quản lý.OperatingSystemMXBean.getProcessCpuTime đến gần (xem đoạn mã tuyệt vời của Patrick ở trên) nhưng lưu ý rằng nó chỉ cung cấp quyền truy cập vào thời gian CPU dành cho quá trình của bạn. nó sẽ không cho bạn biết về thời gian CPU dành cho các quy trình khác, hoặc thậm chí thời gian CPU dành cho các hoạt động hệ thống liên quan đến quy trình của bạn.

ví dụ, tôi có một quy trình java chuyên sâu về mạng - đó là điều duy nhất đang chạy và CPU ở mức 99% nhưng chỉ 55% trong số đó được báo cáo là "CPU bộ xử lý".

thậm chí đừng bắt tôi sử dụng "tải trung bình" vì nó bên cạnh vô dụng, mặc dù là mục duy nhất liên quan đến cpu trên bean MX. nếu chỉ mặt trời trong trí tuệ thỉnh thoảng của họ phơi bày một cái gì đó như "getTotalCpuTime" ...

Đối với giám sát CPU nghiêm trọng SIGAR được đề cập bởi Matt dường như đặt cược tốt nhất.


4

Bật Windows, bạn có thể chạy systeminfolệnh và lấy ví dụ đầu ra của nó với đoạn mã sau:

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

Nếu bạn đang sử dụng Jrockit VM thì đây là một cách khác để sử dụng CPU VM. Thời gian chạy bean cũng có thể cung cấp cho bạn tải CPU trên mỗi bộ xử lý. Tôi đã chỉ sử dụng điều này trên Red Hat Linux để quan sát hiệu suất Tomcat. Bạn phải kích hoạt điều khiển từ xa JMX trong catalina.sh để nó hoạt động.

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

Nó vẫn đang được phát triển nhưng bạn đã có thể sử dụng jHardware

Nó là một thư viện đơn giản giúp loại bỏ dữ liệu hệ thống bằng Java. Nó hoạt động trong cả Linux và 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());
//[...]

Đẹp, nhưng nó sử dụng các phiên bản Guava và JNA mâu thuẫn với nhu cầu của tôi (ví dụ: xem GLASSFISH-21367 ).
lu_ko

Xin chào, JNA đã được giới thiệu trong phiên bản 0.8 của jHardware. Nó chỉ được sử dụng cho dữ liệu nhiệt độ và cảm biến. Nếu bạn không cần thông tin đó, bạn có thể sử dụng phiên bản 0.7. Điều tương tự cho ổi. Trong trường hợp đó, bạn sẽ phải sử dụng phiên bản 0.6.3.
profesor_falken

2

Một cách đơn giản có thể được sử dụng để lấy thông tin cấp độ hệ điều hành và tôi đã thử nghiệm trên máy Mac của mình, nó hoạt động tốt:

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

Bạn có thể tìm thấy nhiều số liệu liên quan của hệ điều hành tại đây


1

Hey bạn có thể làm điều này với tích hợp java / com. Bằng cách truy cập các tính năng WMI, bạn có thể nhận được tất cả thông tin.


0

Để lấy trung bình Tải hệ thống trong 1 phút, 5 phút và 15 phút bên trong mã java, bạn có thể thực hiện việc này bằng cách thực hiện lệnh cat /proc/loadavgbằng cách sử dụng và diễn giải nó như dưới đây:

    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));

Và để có được bộ nhớ hệ thống vật lý bằng cách thực hiện lệnh free -mvà sau đó diễn giải nó như dưới đây:

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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.