Obtenir des informations système au niveau du système d'exploitation

232

Je construis actuellement une application Java qui pourrait finir par être exécutée sur de nombreuses plates-formes différentes, mais principalement des variantes de Solaris, Linux et Windows.

Quelqu'un a-t-il réussi à extraire des informations telles que l'espace disque actuellement utilisé, l'utilisation du processeur et la mémoire utilisée dans le système d'exploitation sous-jacent? Qu'en est-il de ce que l'application Java elle-même consomme?

De préférence, j'aimerais obtenir ces informations sans utiliser JNI.

Steve M
la source
3
En ce qui concerne la mémoire libre, voir stackoverflow.com/a/18366283/231397 ( Runtime.getRuntime().freeMemory()comme suggéré dans la réponse acceptée NE VOUS donne PAS la quantité de mémoire disponible.
Christian Fries

Réponses:

206

Vous pouvez obtenir des informations sur la mémoire limitée de la classe Runtime. Ce n'est vraiment pas exactement ce que vous recherchez, mais j'ai pensé que je le fournirais par souci d'exhaustivité. Voici un petit exemple. Modifier: vous pouvez également obtenir des informations sur l'utilisation du disque à partir de la classe java.io.File. L'utilisation de l'espace disque nécessite Java 1.6 ou supérieur.

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
la source
7
Je pense que "la mémoire totale actuellement utilisée par la JVM" est un peu déroutante. Le javadoc indique que la fonction renvoie "la quantité totale de mémoire actuellement disponible pour les objets actuels et futurs, mesurée en octets". Cela ressemble plus à la mémoire restante et non utilisée.
Dirk
@Dirk: J'ai mis à jour le libellé pour répondre à votre commentaire. Merci!
William Brendel
@LeonardoGaldioli: Je ne connais pas les caractéristiques de performance de ces classes et méthodes, mais je ne serais pas surpris si elles n'étaient pas optimisées pour la vitesse. D'autres réponses expliquent comment collecter certaines informations à l'aide de JMX, ce qui pourrait être plus rapide.
William Brendel
15
Cela ne répond pas correctement à la question. Toutes ces données se retrouvent sur la JVM et non sur le système d'exploitation ...
Alvaro
Je sais que ce sujet est assez dépassé. MAIS: Si vous avez vraiment besoin de la quantité de cœurs de processeur, n'utilisez pas cette solution. J'ai un processeur double cœur avec deux threads pour chaque cœur. La JVM ne renvoie pas les cœurs matériels, mais plutôt les cœurs / threads logiciels.
F_Schmidt
95

Le package java.lang.management vous donne beaucoup plus d'informations que Runtime - par exemple, il vous donnera une mémoire de tas ( ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()) distincte de la mémoire non de tas ( ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage()).

Vous pouvez également obtenir l'utilisation du processeur du processus (sans écrire votre propre code JNI), mais vous devez convertir le java.lang.management.OperatingSystemMXBeanen a com.sun.management.OperatingSystemMXBean. Cela fonctionne sur Windows et Linux, je ne l'ai pas testé ailleurs.

Par exemple ... appelez la méthode get getCpuUsage () plus fréquemment pour obtenir des lectures plus précises.

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
la source
10
Pour le compiler, remplacez le transtypage OperatingSystemMXBeanen com.sun.management.OperatingSystemMXBeanet faites précéder toutes les instances de getOperatingSystemMXBean()avec ManagementFactory.. Vous devez importer toutes les classes de manière appropriée.
tmarthal
2
j'obtiens l'utilisation d'unité centrale de traitement comme 0 pour tout. j'ai changé la formule d'utilisation de cpu en cpuUsage = processCpuTime / systemTime. je reçois une valeur pour l'utilisation du processeur que je ne comprends pas.
Raj
t 1,0 comme résultat de la getCpuUsagemoyenne que le système utilise toutes ses availableProcessors à 100%?
user454322
2
J'ai toujours 0 comme @Raj l'a dit ... pourriez-vous donner un exemple de la façon d'utiliser ce code?
dm76
1
Essayez((double)( processCpuTime - lastProcessCpuTime )) / ((double)( systemTime - lastSystemTime ))
Anthony O.
43

Je pense que la meilleure méthode est d'implémenter l' API SIGAR par Hyperic . Il fonctionne pour la plupart des principaux systèmes d'exploitation (sacrément proche de tout ce qui est moderne) et est très facile à utiliser. Les développeurs sont très réactifs sur leur forum et leurs listes de diffusion. J'aime aussi le fait qu'il soit sous licence GPL2 Apache . Ils fournissent également une tonne d'exemples en Java!

SIGAR == Outil d'information, de collecte et de rapport sur le système.

Matt Cummings
la source
2
@Yohan - Ne soyez pas paresseux! Vous pouvez le découvrir en lisant la page Web liée. (Et cela dépend de ce que vous entendez par "indépendant de la plate-forme".)
Stephen C
2
@StephenC: Sigar utilise des fichiers .dll, ce qui le rend dépendant de la plateforme. L'API de niveau supérieur peut être en Java, c'est une autre histoire
Lemon Juice
1
@Artificial_Intelligence oui, mais il fournit des bibliothèques (écrites en c) pour les plateformes les plus populaires. Il n'est pas plus dépendant de la plateforme que le jvm lui-même. L'API Java de niveau supérieur doit être cohérente sur toutes les plates-formes.
Jeshurun
8
Sigar n'a pas été mis à jour depuis 2010 et semble avoir un bug sur les systèmes 64 bits: stackoverflow.com/questions/23405832/…
Alvaro
1
Et SIGAR fait également planter la JVM (bien qu'intermittent) mais je suis sûr que vous ne prendrez pas ce risque en production.
AKS
25

Il existe un projet Java qui utilise JNA (donc aucune bibliothèque native à installer) et est en développement actif. Il prend actuellement en charge Linux, OSX, Windows, Solaris et FreeBSD et fournit des informations sur la RAM, le processeur, la batterie et le système de fichiers.

dB.
la source
Aucune bibliothèque native n'est peut-être trompeuse. Le projet utilise des bibliothèques natives, même si elles n'en ont pas écrit, et vous n'avez apparemment pas besoin d'en installer.
Stephen C
1
Vous avez raison. JNA utilise libffi qui a des composants natifs. Mais à toutes fins utiles, il semble qu'il n'y ait pas de bibliothèques natives (certainement aucune à installer).
dB.
@StephenC bien que ce que vous dites soit précis, c'est trompeur car c'est la même chose pour rt.jar qui invoque également des méthodes natives. la seule raison pour laquelle les gens se soucient des méthodes natives est qu'ils doivent les compiler et / ou les installer, ce qui est souvent une tâche non triviale. puisque libffi est si largement adopté, porté et installé, il atténue les difficultés. Donc, techniquement, vous avez raison, mais pratiquement, cela n'a pas d'importance.
rbp
@rbp - Les développeurs Java expérimentés préfèrent éviter les bibliothèques natives pour une autre raison . Une bibliothèque native contenant des bogues (y compris des problèmes de sécurité des threads ou des problèmes de gestion de la mémoire) est susceptible de déstabiliser la machine virtuelle Java hôte. Ce n'est pas un problème "ça n'a pas d'importance" ....
Stephen C
@StephenC est-ce que le fait d'avoir créé le serveur d'applications weblogic me rend assez expérimenté ?
rbp
13

Pour les fenêtres, je suis allé de cette façon.

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

Voici le lien avec les détails.

Yan Khonski
la source
11

Vous pouvez obtenir des informations au niveau du système en utilisant System.getenv(), en passant le nom de la variable d'environnement appropriée en tant que paramètre. Par exemple, sous Windows:

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

Pour les autres systèmes d'exploitation, la présence / absence et les noms des variables d'environnement pertinentes différeront.

Alexandr
la source
1
Ceux-ci dépendent de la plate-forme car les noms de variables sont différents d'un système à l'autre. Un article d'Oracle sur les variables d'environnement le dit. Je trouve également un moyen d'obtenir un système indépendant.
Lemon Juice
Sous Linux (Ubuntu 17.10), il n'y a pas beaucoup d'informations intéressantes concernant les processeurs dans l'environnement.
pveentjer
8

Ajouter une dépendance OSHI via maven:

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

Obtenez une capacité de batterie restante en pourcentage:

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
la source
L'OSHI possède la plupart des informations décrites dans les autres commentaires. Il utilise JNA pour l'obtenir via des appels natifs du système d'exploitation lorsque cela est possible.
Daniel Widdis
6

Jetez un œil aux API disponibles dans le package java.lang.management . Par exemple:

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

Il y a aussi plein d'autres choses utiles.

staffan
la source
2
OperatingSystemMXBean.getSystemLoadAverage () n'est pas implémenté dans Windows car "c'est trop cher"
MikeNereson
1
ThreadMXBean.getCurrentThreadCpuTime () renvoie uniquement la durée de fonctionnement de ce thread. Pas le pourcentage d'utilisation du processeur.
MikeNereson
5

Habituellement, pour obtenir des informations de bas niveau sur le système d'exploitation, vous pouvez appeler des commandes spécifiques au système d'exploitation qui vous donnent les informations souhaitées avec Runtime.exec () ou lire des fichiers tels que / proc / * sous Linux.

Peter Lawrey
la source
5

L'utilisation du processeur n'est pas simple - java.lang.management via com.sun.management.OperatingSystemMXBean.getProcessCpuTime se rapproche (voir l'excellent extrait de code de Patrick ci-dessus), mais notez qu'il ne donne accès qu'au temps passé par le processeur dans votre processus. il ne vous indiquera pas le temps processeur passé dans d'autres processus, ni même le temps processeur consacré aux activités système liées à votre processus.

par exemple, j'ai un processus java intensif en réseau - c'est la seule chose qui fonctionne et le CPU est à 99% mais seulement 55% de cela est rapporté comme "CPU processeur".

ne me lancez même pas sur la «moyenne de charge» car elle est presque inutile, bien qu'elle soit le seul élément lié au processeur sur le bean MX. si seulement le soleil dans sa sagesse occasionnelle exposait quelque chose comme "getTotalCpuTime" ...

pour une surveillance sérieuse du CPU, SIGAR mentionné par Matt semble le meilleur choix.

Partiellement nuageux
la source
4

Sur Windows, vous pouvez exécuter la systeminfocommande et récupérer sa sortie par exemple avec le code suivant:

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
la source
3

Si vous utilisez Jrockit VM, voici une autre façon d'obtenir l'utilisation du processeur VM. Le bean Runtime peut également vous donner une charge CPU par processeur. Je l'ai utilisé uniquement sur Red Hat Linux pour observer les performances de Tomcat. Vous devez activer la télécommande JMX dans catalina.sh pour que cela fonctionne.

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
la source
3

Il est encore en cours de développement mais vous pouvez déjà utiliser jHardware

Il s'agit d'une bibliothèque simple qui supprime les données système à l'aide de Java. Il fonctionne à la fois sous Linux et 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
la source
Bien, mais il utilise des versions de Guava et JNA qui sont en conflit avec mes besoins (voir par exemple GLASSFISH-21367 ).
lu_ko
Bonjour, JNA a été introduit dans la version 0.8 de jHardware. Il est uniquement utilisé pour les données de température et de capteurs. Si vous n'avez pas besoin de ces informations, vous pouvez utiliser la version 0.7. Même chose pour la goyave. Dans ce cas, vous devrez utiliser la version 0.6.3.
profesor_falken
2

Un moyen simple qui peut être utilisé pour obtenir les informations de niveau OS et j'ai testé dans mon Mac qui fonctionne bien:

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

Vous pouvez trouver de nombreuses mesures pertinentes du système d'exploitation ici

Amandeep Singh
la source
1

Hé, vous pouvez le faire avec l'intégration java / com. En accédant aux fonctionnalités WMI, vous pouvez obtenir toutes les informations.


la source
0

Pour obtenir la moyenne de charge système de 1 minute, 5 minutes et 15 minutes à l'intérieur du code java, vous pouvez le faire en exécutant la commande à l' cat /proc/loadavgaide et en l'interprétant comme ci-dessous:

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

Et pour obtenir la mémoire du système physique en exécutant la commande free -mpuis en l'interprétant comme ci-dessous:

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
la source