Dapatkan informasi sistem tingkat OS

232

Saat ini saya sedang membangun aplikasi Java yang akhirnya bisa dijalankan pada banyak platform yang berbeda, tetapi terutama varian Solaris, Linux dan Windows.

Adakah yang berhasil mengekstraksi informasi seperti ruang disk saat ini yang digunakan, pemanfaatan CPU, dan memori yang digunakan dalam OS yang mendasarinya? Bagaimana dengan apa yang dikonsumsi aplikasi Java itu sendiri?

Lebih disukai saya ingin mendapatkan informasi ini tanpa menggunakan JNI.

Steve M
sumber
3
Sehubungan dengan memori bebas lihat stackoverflow.com/a/18366283/231397 ( Runtime.getRuntime().freeMemory()seperti yang disarankan dalam jawaban yang diterima TIDAK memberi Anda jumlah memori bebas.
Christian Fries

Jawaban:

206

Anda bisa mendapatkan beberapa informasi memori terbatas dari kelas Runtime. Sebenarnya bukan apa yang Anda cari, tapi saya pikir saya akan menyediakannya demi kelengkapan. Ini adalah contoh kecil. Sunting: Anda juga bisa mendapatkan informasi penggunaan disk dari kelas java.io.File. Hal-hal penggunaan ruang disk memerlukan Java 1.6 atau lebih tinggi.

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());
    }
  }
}
William Brendel
sumber
7
Saya pikir "Total memori yang saat ini digunakan oleh JVM" agak membingungkan. The javadoc mengatakan bahwa fungsi kembali "jumlah total memori saat ini tersedia untuk saat ini dan masa depan objek, diukur dalam byte." Terdengar lebih seperti memori yang tersisa dan tidak digunakan.
Dirk
@ Gang: Saya memperbarui kata-kata untuk menanggapi komentar Anda. Terima kasih!
William Brendel
@LeonardoGaldioli: Saya tidak tahu karakteristik kinerja dari kelas dan metode ini, tapi saya tidak akan terkejut jika mereka tidak dioptimalkan untuk kecepatan. Jawaban lain menjelaskan cara mengumpulkan informasi tertentu menggunakan JMX, yang mungkin lebih cepat.
William Brendel
15
Ini tidak menjawab pertanyaan dengan benar. Semua itu data reefers ke JVM dan bukan ke OS ...
Alvaro
Saya tahu bahwa topik ini sudah usang. TAPI: Jika Anda benar-benar membutuhkan jumlah inti cpu, maka jangan gunakan solusi ini. Saya memiliki CPU dual-core dengan dua utas untuk setiap inti. JVM tidak mengembalikan inti perangkat keras, melainkan inti perangkat lunak / utas.
F_Schmidt
95

The java.lang.management paket tidak memberikan info lebih banyak daripada Runtime - misalnya itu akan memberikan memori tumpukan ( ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()) terpisah dari memori non-tumpukan ( ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage()).

Anda juga bisa mendapatkan proses penggunaan CPU (tanpa menulis kode JNI Anda sendiri), tetapi Anda harus menggunakan java.lang.management.OperatingSystemMXBeana com.sun.management.OperatingSystemMXBean. Ini berfungsi pada Windows dan Linux, saya belum mengujinya di tempat lain.

Misalnya ... panggil metode get getCpuUsage () lebih sering untuk mendapatkan pembacaan yang lebih akurat.

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();
        }
    }
}
Patrick Wilkes
sumber
10
Untuk membuatnya dikompilasi, ganti gips OperatingSystemMXBeanke com.sun.management.OperatingSystemMXBeandan kata pengantar semua contoh getOperatingSystemMXBean()dengan ManagementFactory.. Anda perlu mengimpor semua kelas dengan tepat.
tmarthal
2
Saya mendapatkan penggunaan CPU sebagai 0 untuk semuanya. saya mengubah rumus penggunaan cpu menjadi cpuUsage = processCpuTime / systemTime. Saya mendapatkan nilai untuk penggunaan CPU yang tidak saya mengerti.
Raj
apakah 1.0 sebagai hasil dari getCpuUsagerata-rata bahwa sistem menggunakan semua Prosesor yang tersedia sebesar 100%?
user454322
2
Saya selalu mendapatkan 0 seperti kata @Raj ... bisakah Anda memberikan contoh cara menggunakan kode itu?
dm76
1
Coba((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
Anthony O.
43

Saya pikir metode terbaik di luar sana adalah mengimplementasikan SIGAR API oleh Hyperic . Ini bekerja untuk sebagian besar sistem operasi utama (sangat dekat dengan apa pun yang modern) dan sangat mudah digunakan. Pengembang sangat responsif terhadap forum dan milis mereka. Saya juga suka bahwa itu adalah lisensi GPL2 Apache . Mereka memberikan banyak contoh di Jawa juga!

SIGAR == Alat Informasi, Pengumpulan Dan Pelaporan Sistem.

Matt Cummings
sumber
2
@Yohan - Jangan malas! Anda dapat menemukannya dengan membaca halaman web yang tertaut. (Dan itu tergantung pada apa yang Anda maksud dengan "platform independent".)
Stephen C
2
@StephenC: Sigar menggunakan file .dll, yang membuatnya bergantung pada platform. Tingkat API yang lebih tinggi mungkin di Jawa, ini adalah cerita yang berbeda
Lemon Juice
1
@Artificial_Intelligence ya, tetapi menyediakan pustaka (ditulis dalam c) untuk platform paling populer. Ini tidak lebih tergantung platform dari jvm itu sendiri. API Java tingkat yang lebih tinggi harus konsisten pada semua platform.
Jeshurun
8
Sigar tidak diperbarui sejak 2010 dan tampaknya memiliki bug pada sistem 64 bit: stackoverflow.com/questions/23405832/…
Alvaro
1
Dan SIGAR membuat crash JVM juga, (meskipun berselang) tetapi saya yakin Anda tidak akan mengambil risiko ini dalam produksi.
AKS
25

Ada proyek Java yang menggunakan JNA (jadi tidak ada perpustakaan asli untuk menginstal) dan sedang dalam pengembangan aktif. Saat ini mendukung Linux, OSX, Windows, Solaris dan FreeBSD dan menyediakan RAM, CPU, Baterai dan informasi sistem file.

dB.
sumber
Tidak ada perpustakaan asli yang menyesatkan. Proyek ini menggunakan pustaka asli, bahkan jika mereka belum menulis apa pun, dan Anda tampaknya tidak perlu menginstalnya.
Stephen C
1
Kamu benar. JNA menggunakan libffi yang memiliki komponen asli. Tetapi untuk semua tujuan, sepertinya tidak ada perpustakaan asli (pasti tidak ada yang menginstal).
dB.
@StephenC walaupun apa yang Anda katakan akurat, menyesatkan karena sama untuk rt.jar yang juga memanggil metode asli. satu-satunya alasan orang peduli tentang metode asli adalah bahwa mereka harus mengkompilasi dan / atau menginstalnya, yang sering kali sering merupakan tugas yang tidak sepele. karena libffi secara luas diadopsi, porting, dan diinstal, libffi mengurangi kesulitan. jadi, secara teknis Anda benar, tetapi secara praktis, itu tidak masalah.
rbp
@rbp - Ada alasan lain mengapa pengembang Java yang berpengalaman memilih untuk menghindari pustaka asli. Pustaka asli yang memiliki bug (termasuk masalah keamanan utas atau masalah dengan manajemen memori) bertanggung jawab untuk mengacaukan JVM tuan rumah. Ini bukan masalah "tidak masalah" ....
Stephen C
@StephenC tidak membuat server aplikasi weblogic membuat saya cukup berpengalaman ?
rbp
13

Untuk windows saya pergi ke sini.

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

Ini tautan dengan detail.

Yan Khonski
sumber
11

Anda bisa mendapatkan beberapa informasi tingkat sistem dengan menggunakan System.getenv(), meneruskan nama variabel lingkungan yang relevan sebagai parameter. Misalnya, di Windows:

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

Untuk sistem operasi lain, ada / tidaknya dan nama variabel lingkungan yang relevan akan berbeda.

Alexandr
sumber
1
Ini tergantung platform karena nama variabel berbeda di antara sistem. Artikel Oracle tentang variabel lingkungan memberitahukan hal itu. Saya juga menemukan cara untuk mendapatkan cara sistem independen.
Jus Lemon
Di Linux (Ubuntu 17.10) tidak ada banyak informasi menarik mengenai prosesor di lingkungan.
pveentjer
8

Tambahkan ketergantungan OSHI melalui pakar:

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

Persentase kapasitas baterai tersisa:

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));
}
Oleksii Kyslytsyn
sumber
OSHI memiliki sebagian besar informasi yang dijelaskan dalam komentar lain. Menggunakan JNA untuk mendapatkannya melalui panggilan asli OS bila memungkinkan.
Daniel Widdis
6

Lihat API yang tersedia di paket manajemen java.lang.man . Sebagai contoh:

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

Ada banyak hal berguna lainnya di sana juga.

staf
sumber
2
OperatingSystemMXBean.getSystemLoadAverage () tidak diimplementasikan di windows karena "terlalu mahal"
MikeNereson
1
ThreadMXBean.getCurrentThreadCpuTime () hanya mengembalikan berapa lama utas tersebut telah berjalan. Bukan persentase penggunaan cpu.
MikeNereson
5

Biasanya, untuk mendapatkan informasi OS tingkat rendah Anda dapat memanggil perintah khusus OS yang memberi Anda informasi yang Anda inginkan dengan Runtime.exec () atau membaca file seperti / proc / * di Linux.

Peter Lawrey
sumber
5

Penggunaan CPU tidak mudah - java.lang.management via com.sun.management.OperatingSystemMXBean.getProcessCpuTime mendekati (lihat cuplikan kode Patrick yang sangat baik di atas) tetapi perhatikan bahwa itu hanya memberikan akses ke waktu yang dihabiskan CPU dalam proses Anda. itu tidak akan memberi tahu Anda tentang waktu CPU yang dihabiskan dalam proses lain, atau bahkan waktu CPU yang dihabiskan untuk melakukan aktivitas sistem yang terkait dengan proses Anda.

misalnya saya punya proses java jaringan-intensif - itu satu-satunya yang berjalan dan CPU pada 99% tetapi hanya 55% dari yang dilaporkan sebagai "prosesor CPU".

bahkan tidak memulai saya pada "rata-rata memuat" karena itu tidak berguna, meskipun menjadi satu-satunya item yang berhubungan dengan cpu pada kacang MX. jika hanya berjemur dalam kebijaksanaan sesekali mereka mengekspos sesuatu seperti "getTotalCpuTime" ...

untuk pemantauan CPU yang serius SIGAR yang disebutkan oleh Matt tampaknya merupakan taruhan terbaik.

Berawan
sumber
4

Pada Windows, Anda dapat menjalankan systeminfoperintah dan mengambil outputnya misalnya dengan kode berikut:

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();
    }
}
BullyWiiPlaza
sumber
3

Jika Anda menggunakan Jrockit VM maka berikut adalah cara lain untuk mendapatkan penggunaan CPU VM. Kacang Runtime juga dapat memberi Anda beban CPU per prosesor. Saya hanya menggunakan ini di Red Hat Linux untuk mengamati kinerja Tomcat. Anda harus mengaktifkan JMX remote di catalina.sh agar ini berfungsi.

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");
petro
sumber
3

Ini masih dalam pengembangan tetapi Anda sudah bisa menggunakan jHardware

Ini adalah perpustakaan sederhana yang memotong data sistem menggunakan Java. Ia bekerja di Linux dan 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());
//[...]
profesor_falken
sumber
Bagus, tetapi menggunakan versi Guava dan JNA yang bertentangan dengan kebutuhan saya (mis. Lihat GLASSFISH-21367 ).
lu_ko
Halo, JNA telah diperkenalkan dalam versi jHardware 0.8. Ini hanya digunakan untuk data suhu dan sensor. Jika Anda tidak memerlukan informasi itu, Anda dapat menggunakan versi 0.7. Hal yang sama untuk Jambu. Dalam hal ini Anda harus menggunakan versi 0.6.3.
profesor_falken
2

Salah satu cara sederhana yang dapat digunakan untuk mendapatkan informasi level OS dan saya uji di Mac saya yang berfungsi dengan baik:

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

Anda dapat menemukan banyak metrik yang relevan dari sistem operasi di sini

Amandeep Singh
sumber
1

Hai Anda dapat melakukan ini dengan integrasi java / com. Dengan mengakses fitur WMI, Anda dapat memperoleh semua informasi.


sumber
0

Untuk mendapatkan System Load rata - rata 1 menit, 5 menit dan 15 menit di dalam kode java, Anda bisa melakukan ini dengan mengeksekusi perintah cat /proc/loadavgmenggunakan dan menafsirkannya seperti di bawah ini:

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

Dan untuk mendapatkan memori sistem fisik dengan mengeksekusi perintah free -mdan kemudian menafsirkannya sebagai berikut:

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);
krishna Prasad
sumber