Comment surveiller l'utilisation du processeur, de la mémoire et du disque de l'ordinateur en Java?

180

Je souhaite surveiller les informations système suivantes en Java:

  • Utilisation actuelle du processeur ** (pourcentage)
  • Mémoire disponible * (libre / totale)
  • Espace disque disponible (libre / total)

    * Notez que je veux dire la mémoire globale disponible pour l'ensemble du système, pas seulement la JVM.

Je recherche une solution multiplateforme (Linux, Mac et Windows) qui ne repose pas sur mon propre code appelant des programmes externes ou utilisant JNI. Bien que ce soient des options viables, je préférerais ne pas gérer moi-même le code spécifique au système d'exploitation si quelqu'un a déjà une meilleure solution.

S'il existe une bibliothèque gratuite qui le fait de manière fiable et multiplateforme, ce serait génial (même si elle effectue des appels externes ou utilise du code natif lui-même).

Les suggestions sont très appréciées.

Pour clarifier, je voudrais obtenir l'utilisation actuelle du processeur pour l'ensemble du système, pas seulement le ou les processus Java.

L'API SIGAR fournit toutes les fonctionnalités que je recherche dans un seul package, c'est donc la meilleure réponse à ma question à ce jour. Cependant, en raison de sa licence sous GPL, je ne peux pas l'utiliser pour mon objectif initial (une source fermée, un produit commercial). Il est possible qu'Hyperic accorde une licence à SIGAR à des fins commerciales, mais je ne l'ai pas examiné. Pour mes projets GPL, je considérerai certainement SIGAR à l'avenir.

Pour mes besoins actuels, je penche vers ce qui suit:

  • Pour l'utilisation du processeur, OperatingSystemMXBean.getSystemLoadAverage() / OperatingSystemMXBean.getAvailableProcessors()(charge moyenne par processeur)
  • Pour mémoire, OperatingSystemMXBean.getTotalPhysicalMemorySize()etOperatingSystemMXBean.getFreePhysicalMemorySize()
  • Pour l'espace disque, File.getTotalSpace()etFile.getUsableSpace()

Limites:

Les getSystemLoadAverage()méthodes d'interrogation de l'espace disque et ne sont disponibles que sous Java 6. De plus, certaines fonctionnalités de JMX peuvent ne pas être disponibles sur toutes les plates-formes (c'est-à-dire qu'il a été signalé qu'elle getSystemLoadAverage()renvoie -1 sous Windows).

Bien que sous licence GPL à l'origine, il a été remplacé par Apache 2.0 , qui peut généralement être utilisé pour des produits commerciaux à source fermée.

David Crow
la source
Pour clarifier, l'API sigar vous obtient des informations système. Si vous voulez des informations jvm, utilisez JMX.
Matt Cummings
SIGAR étant sous GPL ne vous empêche pas de l'utiliser, cela signifie simplement que vous devez contacter les auteurs et demander une licence alternative. Les auteurs acceptent souvent volontiers une somme modique et autorisent les licences commerciales.
Alec Thomas
7
Depuis la version 1.6.4, SIGAR utilise la licence Apache.
Soundlink
savez-vous comment obtenir la charge pour chaque processeur individuel?
zcaudate

Réponses:

67

Dans le sens de ce que j'ai mentionné dans cet article . Je vous recommande d'utiliser l' API SIGAR . J'utilise l'API SIGAR dans l'une de mes propres applications et c'est génial. Vous trouverez qu'il est stable, bien pris en charge et plein d'exemples utiles. Il est open-source avec une licence GPL 2 Apache 2.0. Vérifiez-le. J'ai le sentiment qu'il répondra à vos besoins.

En utilisant Java et l'API Sigar, vous pouvez obtenir la mémoire, le processeur, le disque, la charge moyenne, les informations et les métriques d'interface réseau, les informations de table de processus, les informations d'itinéraire, etc.

Matt Cummings
la source
14
Soyez prudent lorsque vous utilisez Sigar, il y a des problèmes sur les machines x64 ... stackoverflow.com/questions/23405832/ ... et il semble que la bibliothèque ne soit pas mise à jour depuis 2010
Alvaro
56

Ce qui suit est censé vous procurer du processeur et de la RAM. Voir ManagementFactory pour plus de détails.

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

private static void printUsage() {
  OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
  for (Method method : operatingSystemMXBean.getClass().getDeclaredMethods()) {
    method.setAccessible(true);
    if (method.getName().startsWith("get")
        && Modifier.isPublic(method.getModifiers())) {
            Object value;
        try {
            value = method.invoke(operatingSystemMXBean);
        } catch (Exception e) {
            value = e;
        } // try
        System.out.println(method.getName() + " = " + value);
    } // if
  } // for
}
Eugene Yokota
la source
3
Exemple de sortie pour le code ci-dessus. Ce code fonctionne sur Java 1.5. getCommittedVirtualMemorySize = 28622848 getFreePhysicalMemorySize = 228462592 getFreeSwapSpaceSize = 1129848832 getProcessCpuTime = 390625000 getTotalPhysicalMemorySize = 2147483647 getTotalSwapSpaceSize = 4294967295
blak3r
AFAIK getProcessCpuTime = 390625000 correspond uniquement à la durée d'exécution de ce thread. Ce n'est pas vraiment utile pour déterminer l'utilisation du processeur
MikeNereson
2
Je ne suis pas sûr que ce soit réellement fiable. Sur Windows XP avec 4 Go de mémoire physique, il ne rapporte que 2 Go (testé avec Java 6 et Java 7). La taille totale du swap est également erronée.
Emmanuel Bourg
4
@EmmanuelBourg juste pour documenter pour les personnes qui voient ce sujet, il y a un bug lié à cela.
Sérgio Michels
2
Cette méthode fonctionnait très bien jusqu'à Java 9, elle lève maintenant une exception java.lang.reflect.InaccessibleObjectException en raison du nouveau cadre de vérification d'accès que Java utilise.
Thor Lancaster
40

Dans JDK 1.7, vous pouvez obtenir l'utilisation du processeur et de la mémoire du système via com.sun.management.OperatingSystemMXBean. C'est différent de java.lang.management.OperatingSystemMXBean.

long    getCommittedVirtualMemorySize()
Returns the amount of virtual memory that is guaranteed to be available to the running process in bytes, or -1 if this operation is not supported.

long    getFreePhysicalMemorySize()
Returns the amount of free physical memory in bytes.

long    getFreeSwapSpaceSize()
Returns the amount of free swap space in bytes.

double  getProcessCpuLoad()
Returns the "recent cpu usage" for the Java Virtual Machine process.

long    getProcessCpuTime()
Returns the CPU time used by the process on which the Java virtual machine is running in nanoseconds.

double  getSystemCpuLoad()
Returns the "recent cpu usage" for the whole system.

long    getTotalPhysicalMemorySize()
Returns the total amount of physical memory in bytes.

long    getTotalSwapSpaceSize()
Returns the total amount of swap space in bytes.
Gp2you
la source
5
On dirait que c'est hasardeux. Obtenir -1 pour la charge du processeur sur FreeBSD 10 et OpenJDK 8.
cen
vérifiez cette question stackoverflow.com/q/19781087/1206998 . il dit qu'il faut quelques secondes pour être efficace. (note: je n'ai pas essayé)
Juh_
25

Cela fonctionne parfaitement pour moi sans aucune API externe, juste une fonctionnalité cachée Java native :)

import com.sun.management.OperatingSystemMXBean;
...
OperatingSystemMXBean osBean = ManagementFactory.getPlatformMXBean(
                OperatingSystemMXBean.class);
// What % CPU load this current JVM is taking, from 0.0-1.0
System.out.println(osBean.getProcessCpuLoad());

// What % load the overall system is at, from 0.0-1.0
System.out.println(osBean.getSystemCpuLoad());
bizzr3
la source
Honnêtement, je trouve que c'est la meilleure réponse, fonctionne sous Linux, donc je suis heureux.
ArsenArsen
1
un indice pourquoi une 2ème invocation montre 0,0? Sur OpenJDK v8.
vorburger
N'oubliez pas: "import java.lang.management.ManagementFactory;"
Bernd
1
getProcessCpuLoad et getSystemCpuLoad me renvoient -1. im using jdk 1.8
Burak Akyıldız
Il n'a pas de méthode pour obtenir le nombre de threads? Vous vous demandez simplement pourquoi?
djangofan
16

Jetez un œil à cet article très détaillé: http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking#UsingaSuninternalclasstogetJVMCPUtime

Pour obtenir le pourcentage de CPU utilisé, il vous suffit de quelques calculs simples:

MBeanServerConnection mbsc = ManagementFactory.getPlatformMBeanServer();

OperatingSystemMXBean osMBean = ManagementFactory.newPlatformMXBeanProxy(
mbsc, ManagementFactory.OPERATING_SYSTEM_MXBEAN_NAME, OperatingSystemMXBean.class);

long nanoBefore = System.nanoTime();
long cpuBefore = osMBean.getProcessCpuTime();

// Call an expensive task, or sleep if you are monitoring a remote process

long cpuAfter = osMBean.getProcessCpuTime();
long nanoAfter = System.nanoTime();

long percent;
if (nanoAfter > nanoBefore)
 percent = ((cpuAfter-cpuBefore)*100L)/
   (nanoAfter-nanoBefore);
else percent = 0;

System.out.println("Cpu usage: "+percent+"%");

Remarque: vous devez importer com.sun.management.OperatingSystemMXBeanet non java.lang.management.OperatingSystemMXBean.

Ludovicc
la source
C'est une très bonne réponse. Toutes les autres techniques donnent des résultats vraiment étranges et peu fiables, mais celle-ci avec une moyenne de fuite a fonctionné comme un charme pour moi.
Fractaly
Lorsque le temps cpu est supérieur au temps écoulé (j'obtiens plus de 100%), est-ce juste à cause du multithreading, ou comment le comprendre?
Lukas Hanacek
8

Pour l'espace disque, si vous disposez de Java 6, vous pouvez utiliser les méthodes getTotalSpace et getFreeSpace sur File. Si vous n'êtes pas sur Java 6, je pense que vous pouvez utiliser Apache Commons IO pour vous y retrouver.

Je ne connais aucun moyen multiplateforme pour obtenir l'utilisation du processeur ou de la mémoire, j'ai peur.

Matt Sheppard
la source
6

Une grande partie de cela est déjà disponible via JMX. Avec Java 5, JMX est intégré et ils incluent un visualiseur de console JMX avec le JDK.

Vous pouvez utiliser JMX pour surveiller manuellement ou appeler des commandes JMX à partir de Java si vous avez besoin de ces informations dans votre propre environnement d'exécution.

Jason Cohen
la source
4
/* YOU CAN TRY THIS TOO */

import java.io.File;
 import java.lang.management.ManagementFactory;
// import java.lang.management.OperatingSystemMXBean;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.management.RuntimeMXBean;
 import java.io.*;
 import java.net.*;
 import java.util.*;
 import java.io.LineNumberReader;
 import java.lang.management.ManagementFactory;
import com.sun.management.OperatingSystemMXBean;
import java.lang.management.ManagementFactory;
import java.util.Random;



 public class Pragati
 {

     public static void printUsage(Runtime runtime)
     {
     long total, free, used;
     int mb = 1024*1024;

     total = runtime.totalMemory();
     free = runtime.freeMemory();
     used = total - free;
     System.out.println("\nTotal Memory: " + total / mb + "MB");
     System.out.println(" Memory Used: " + used / mb + "MB");
     System.out.println(" Memory Free: " + free / mb + "MB");
     System.out.println("Percent Used: " + ((double)used/(double)total)*100 + "%");
     System.out.println("Percent Free: " + ((double)free/(double)total)*100 + "%");
    }
    public static void log(Object message)
         {
            System.out.println(message);
         }

        public static int calcCPU(long cpuStartTime, long elapsedStartTime, int cpuCount)
        {
             long end = System.nanoTime();
             long totalAvailCPUTime = cpuCount * (end-elapsedStartTime);
             long totalUsedCPUTime = ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime()-cpuStartTime;
             //log("Total CPU Time:" + totalUsedCPUTime + " ns.");
             //log("Total Avail CPU Time:" + totalAvailCPUTime + " ns.");
             float per = ((float)totalUsedCPUTime*100)/(float)totalAvailCPUTime;
             log( per);
             return (int)per;
        }

        static boolean isPrime(int n)
        {
     // 2 is the smallest prime
            if (n <= 2)
            {
                return n == 2;
            }
     // even numbers other than 2 are not prime
            if (n % 2 == 0)
            {
                return false;
            }
     // check odd divisors from 3
     // to the square root of n
         for (int i = 3, end = (int)Math.sqrt(n); i <= end; i += 2)
         {
            if (n % i == 0)
         {
         return false;
        }
        }
 return true;
}
    public static void main(String [] args)
    {
            int mb = 1024*1024;
            int gb = 1024*1024*1024;
             /* PHYSICAL MEMORY USAGE */
             System.out.println("\n**** Sizes in Mega Bytes ****\n");
            com.sun.management.OperatingSystemMXBean operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean)ManagementFactory.getOperatingSystemMXBean();
            //RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
            //operatingSystemMXBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
            com.sun.management.OperatingSystemMXBean os = (com.sun.management.OperatingSystemMXBean)
            java.lang.management.ManagementFactory.getOperatingSystemMXBean();
            long physicalMemorySize = os.getTotalPhysicalMemorySize();
            System.out.println("PHYSICAL MEMORY DETAILS \n");
            System.out.println("total physical memory : " + physicalMemorySize / mb + "MB ");
            long physicalfreeMemorySize = os.getFreePhysicalMemorySize();
            System.out.println("total free physical memory : " + physicalfreeMemorySize / mb + "MB");
            /* DISC SPACE DETAILS */
            File diskPartition = new File("C:");
            File diskPartition1 = new File("D:");
            File diskPartition2 = new File("E:");
            long totalCapacity = diskPartition.getTotalSpace() / gb;
            long totalCapacity1 = diskPartition1.getTotalSpace() / gb;
            double freePartitionSpace = diskPartition.getFreeSpace() / gb;
            double freePartitionSpace1 = diskPartition1.getFreeSpace() / gb;
            double freePartitionSpace2 = diskPartition2.getFreeSpace() / gb;
            double usablePatitionSpace = diskPartition.getUsableSpace() / gb;
            System.out.println("\n**** Sizes in Giga Bytes ****\n");
            System.out.println("DISC SPACE DETAILS \n");
            //System.out.println("Total C partition size : " + totalCapacity + "GB");
            //System.out.println("Usable Space : " + usablePatitionSpace + "GB");
            System.out.println("Free Space in drive C: : " + freePartitionSpace + "GB");
            System.out.println("Free Space in drive D:  : " + freePartitionSpace1 + "GB");
            System.out.println("Free Space in drive E: " + freePartitionSpace2 + "GB");
            if(freePartitionSpace <= totalCapacity%10 || freePartitionSpace1 <= totalCapacity1%10)
            {
                System.out.println(" !!!alert!!!!");
            }
            else
                System.out.println("no alert");

            Runtime runtime;
            byte[] bytes;
            System.out.println("\n \n**MEMORY DETAILS  ** \n");
            // Print initial memory usage.
            runtime = Runtime.getRuntime();
            printUsage(runtime);

            // Allocate a 1 Megabyte and print memory usage
            bytes = new byte[1024*1024];
            printUsage(runtime);

            bytes = null;
            // Invoke garbage collector to reclaim the allocated memory.
            runtime.gc();

            // Wait 5 seconds to give garbage collector a chance to run
            try {
            Thread.sleep(5000);
            } catch(InterruptedException e) {
            e.printStackTrace();
            return;
            }

            // Total memory will probably be the same as the second printUsage call,
            // but the free memory should be about 1 Megabyte larger if garbage
            // collection kicked in.
            printUsage(runtime);
            for(int i = 0; i < 30; i++)
                     {
                         long start = System.nanoTime();
                        // log(start);
                        //number of available processors;
                         int cpuCount = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors();
                         Random random = new Random(start);
                         int seed = Math.abs(random.nextInt());
                         log("\n \n CPU USAGE DETAILS \n\n");
                         log("Starting Test with " + cpuCount + " CPUs and random number:" + seed);
                         int primes = 10000;
                         //
                         long startCPUTime = ManagementFactory.getThreadMXBean().getCurrentThreadCpuTime();
                         start = System.nanoTime();
                         while(primes != 0)
                         {
                            if(isPrime(seed))
                            {
                                primes--;
                            }
                            seed++;

                        }
                         float cpuPercent = calcCPU(startCPUTime, start, cpuCount);
                         log("CPU USAGE : " + cpuPercent + " % ");


                         try
                         {
                             Thread.sleep(1000);
                         }
                         catch (InterruptedException e) {}
        }

            try
            {
                Thread.sleep(500);
            }`enter code here`
            catch (Exception ignored) { }
        }
    }
pragati
la source
4

Le code suivant est uniquement Linux (peut-être Unix), mais il fonctionne dans un vrai projet.

    private double getAverageValueByLinux() throws InterruptedException {
    try {

        long delay = 50;
        List<Double> listValues = new ArrayList<Double>();
        for (int i = 0; i < 100; i++) {
            long cput1 = getCpuT();
            Thread.sleep(delay);
            long cput2 = getCpuT();
            double cpuproc = (1000d * (cput2 - cput1)) / (double) delay;
            listValues.add(cpuproc);
        }
        listValues.remove(0);
        listValues.remove(listValues.size() - 1);
        double sum = 0.0;
        for (Double double1 : listValues) {
            sum += double1;
        }
        return sum / listValues.size();
    } catch (Exception e) {
        e.printStackTrace();
        return 0;
    }

}

private long getCpuT throws FileNotFoundException, IOException {
    BufferedReader reader = new BufferedReader(new FileReader("/proc/stat"));
    String line = reader.readLine();
    Pattern pattern = Pattern.compile("\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)\\D+(\\d+)")
    Matcher m = pattern.matcher(line);

    long cpuUser = 0;
    long cpuSystem = 0;
    if (m.find()) {
        cpuUser = Long.parseLong(m.group(1));
        cpuSystem = Long.parseLong(m.group(3));
    }
    return cpuUser + cpuSystem;
}
Charis Theo
la source
1
C'est en fait ce que je cherchais, mais le code ne contient pas le modèle REGEX pour trouver les informations du processeur dans / proc / stat
Donal Tobin
quel est le modèle ??
HCarrasko
3

Créez un fichier de commandes "Pc.bat" sous la forme, typeperf -sc 1 "\ mukit \ processor (_Total) \ %% Processor Time"

Vous pouvez utiliser la classe MProcess,

/ *
 *Maryland. Mukit Hasan
 * CSE-JU, 35 ans
 ** / import java . io . *;

public class MProcessor {

public MProcessor() { String s; try { Process ps = Runtime.getRuntime().exec("Pc.bat"); BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream())); while((s = br.readLine()) != null) { System.out.println(s); } } catch( Exception ex ) { System.out.println(ex.toString()); } }

}

Ensuite, après quelques manipulations de chaînes, vous obtenez l'utilisation du processeur. Vous pouvez utiliser le même processus pour d'autres tâches.

--Mukit Hasan

Md. Mukit Hasan
la source
1
pour moi (Win XP), la ligne de commande appropriée était: typeperf "\processor(_total)\% processor time"Si vous le mettez dans un fichier batch, utilisez %% au lieu de%. J'ai utilisé technet.microsoft.com/en-us/library/bb490960.aspx .
tutejszy