De vraies différences entre «java -server» et «java -client»?

394

Existe-t-il une réelle différence pratique entre "java -server" et "java -client"?

Tout ce que je peux trouver sur le site de Sun est un vague

msgstr "-server démarre plus lentement mais devrait fonctionner plus vite".

Quelles sont les vraies différences? (Utilisation de JDK 1.6.0_07 actuellement.)

Paul Tomblin
la source

Réponses:

368

Ceci est vraiment lié à HotSpot et aux valeurs d'option par défaut ( Java HotSpot VM Options ) qui diffèrent entre la configuration du client et celle du serveur.

Extrait du chapitre 2 du livre blanc ( L'architecture Java HotSpot Performance Engine ):

Le JDK comprend deux versions de la machine virtuelle: une offre côté client et une machine virtuelle adaptée aux applications serveur. Ces deux solutions partagent la base de code de l'environnement d'exécution Java HotSpot, mais utilisent des compilateurs différents qui sont adaptés aux caractéristiques de performance distinctement uniques des clients et des serveurs. Ces différences incluent la politique de compilation en ligne et les valeurs par défaut du tas.

Bien que le serveur virtuel et les machines virtuelles clientes soient similaires, la machine virtuelle serveur a été spécialement réglée pour maximiser la vitesse de fonctionnement maximale. Il est conçu pour exécuter des applications serveur de longue durée, qui nécessitent la vitesse de fonctionnement la plus rapide possible plus qu'un temps de démarrage rapide ou une plus petite empreinte mémoire d'exécution.

Le compilateur VM client sert de mise à niveau à la fois pour la machine virtuelle classique et les compilateurs juste à temps (JIT) utilisés par les versions précédentes du JDK. La machine virtuelle cliente offre des performances d'exécution améliorées pour les applications et les applets. La machine virtuelle Java HotSpot Client a été spécialement optimisée pour réduire le temps de démarrage des applications et l'empreinte mémoire, ce qui la rend particulièrement adaptée aux environnements clients. En général, le système client est meilleur pour les interfaces graphiques.

La vraie différence se situe donc également au niveau du compilateur:

Le compilateur VM client n'essaie pas d'exécuter bon nombre des optimisations les plus complexes effectuées par le compilateur dans la VM serveur, mais en échange, il nécessite moins de temps pour analyser et compiler un morceau de code. Cela signifie que la machine virtuelle cliente peut démarrer plus rapidement et nécessite une plus petite empreinte mémoire.

La machine virtuelle du serveur contient un compilateur adaptatif avancé qui prend en charge bon nombre des mêmes types d'optimisations effectuées en optimisant les compilateurs C ++, ainsi que certaines optimisations qui ne peuvent pas être effectuées par les compilateurs traditionnels, telles que l'incrustation agressive entre les invocations de méthodes virtuelles. Il s'agit d'un avantage concurrentiel et de performance par rapport aux compilateurs statiques. La technologie d'optimisation adaptative est très flexible dans son approche et surpasse généralement même les techniques avancées d'analyse statique et de compilation.

Remarque: La version de jdk6 update 10 (voir Update Release Notes: Changes in 1.6.0_10 ) a essayé d'améliorer le temps de démarrage, mais pour une raison différente de celle des options de hotspot, étant emballée différemment avec un noyau beaucoup plus petit.


G. Demecki souligne dans les commentaires que dans les versions 64 bits de JDK, l' -clientoption est ignorée pendant de nombreuses années.
Voir la commande Windowsjava :

-client

Sélectionne la machine virtuelle Java HotSpot Client.
Un JDK compatible 64 bits ignore actuellement cette option et utilise à la place la machine virtuelle Java Hotspot Server .

VonC
la source
7
jdk6 update 10 et les versions ultérieures ont un processus d'arrière-plan qui conserve les bibliothèques d'exécution en mémoire, ce qui permet un démarrage beaucoup plus rapide pour les nouveaux processus que d'avoir à tout mettre en page à la demande.
Thorbjørn Ravn Andersen
1
Je pensais que le client vm s'était aussi montré agressif, eh bien.
Thorbjørn Ravn Andersen
1
Je pense que cette réponse devrait être mise à jour. Parce que sur les versions 64 bits de JDK, l' -clientoption est ignorée pendant de nombreuses années.
G. Demecki
@ G.Demecki Bien sûr: avez-vous un lien documentant que cette option est obsolète ou ignorée?
VonC
1
Sûr. Voici une documentation pour Java 7 pour Windows. Et étonnamment, une information similaire peut également être trouvée dans la documentation Java 6 .
G. Demecki
90

La différence immédiate la plus visible dans les anciennes versions de Java serait la mémoire allouée à un -clientpar opposition à une -serverapplication. Par exemple, sur mon système Linux, j'obtiens:

$ java -XX:+PrintFlagsFinal -version 2>&1 | grep -i -E 'heapsize|permsize|version'
uintx AdaptivePermSizeWeight               = 20               {product}
uintx ErgoHeapSizeLimit                    = 0                {product}
uintx InitialHeapSize                     := 66328448         {product}
uintx LargePageHeapSizeThreshold           = 134217728        {product}
uintx MaxHeapSize                         := 1063256064       {product}
uintx MaxPermSize                          = 67108864         {pd product}
uintx PermSize                             = 16777216         {pd product}
java version "1.6.0_24"

comme par défaut -server, mais avec l' -clientoption que j'obtiens:

$ java -client -XX:+PrintFlagsFinal -version 2>&1 | grep -i -E 'heapsize|permsize|version'
uintx AdaptivePermSizeWeight               = 20               {product}
uintx ErgoHeapSizeLimit                    = 0                {product}
uintx InitialHeapSize                     := 16777216         {product}
uintx LargePageHeapSizeThreshold           = 134217728        {product}
uintx MaxHeapSize                         := 268435456        {product}
uintx MaxPermSize                          = 67108864         {pd product}
uintx PermSize                             = 12582912         {pd product}
java version "1.6.0_24"

donc avec la -serverplupart des limites de mémoire et les allocations initiales sont beaucoup plus élevées pour cette javaversion.

Cependant, ces valeurs peuvent changer pour différentes combinaisons d'architecture, de système d'exploitation et de version jvm. Les versions récentes de jvm ont supprimé les indicateurs et supprimé de nombreuses distinctions entre serveur et client.

N'oubliez pas non plus que vous pouvez voir tous les détails d'une course à l' jvmaide de jvisualvm. Ceci est utile si vous avez des utilisateurs ou des modules qui définissent JAVA_OPTSou utilisent des scripts qui modifient les options de ligne de commande. Cela vous permettra également de surveiller, en temps réel, l'utilisation de l'espace de tas et de permgen ainsi que de nombreuses autres statistiques.

Mark Booth
la source
2
Il me donne les mêmes chiffres sur les modes -serveur et -client pour la version java "1.7.0_79" sur CentOS 7 [Java (TM) SE Runtime Environment (build 1.7.0_79-b15) Java HotSpot (TM) 64-Bit Server VM ]
Basil Musa
4
C'est pourquoi j'ai fourni la réponse. Il ne s'agit pas de valeurs, il s'agit de permettre à n'importe qui, à tout moment, de trouver la réponse pour sa version jvm spécifique.
Mark Booth
33

les systèmes -client et -server sont des binaires différents. Il s'agit essentiellement de deux compilateurs différents (JIT) s'interfaçant au même système d'exécution. Le système client est optimal pour les applications qui nécessitent des temps de démarrage rapides ou de petites empreintes, le système serveur est optimal pour les applications où les performances globales sont les plus importantes. En général, le système client est mieux adapté aux applications interactives telles que les interfaces graphiques

entrez la description de l'image ici

Nous exécutons le code suivant avec les deux commutateurs:

package com.blogspot.sdoulger;

public class LoopTest {
    public LoopTest() {
        super();
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        spendTime();
        long end = System.currentTimeMillis();
        System.out.println("Time spent: "+ (end-start));

        LoopTest loopTest = new LoopTest();
    }

    private static void spendTime() {
        for (int i =500000000;i>0;i--) {
        }
    }
}

Remarque: Le code n'a été compilé qu'une seule fois! Les classes sont les mêmes dans les deux runs!

Avec -client:
java.exe -client -classpath C: \ mywork \ classes com.blogspot.sdoulger.LoopTest
Temps passé: 766

Avec -server:
java.exe -server -classpath C: \ mywork \ classes com.blogspot.sdoulger.LoopTest
Temps passé: 0

Il semble que l'optimisation la plus agressive du système serveur, supprime la boucle car elle comprend qu'elle n'effectue aucune action!

Référence

Premraj
la source
33

Une différence que je viens de remarquer est qu'en mode "client", il semble que la JVM redonne en fait de la mémoire inutilisée au système d'exploitation, alors qu'avec le mode "serveur", une fois que la JVM récupère la mémoire, elle ne la lui donnera pas retour. C'est de cette façon qu'il apparaît sur Solaris avec Java6 de toute façon (en utilisant prstat -Zpour voir la quantité de mémoire allouée à un processus).

prule
la source
22

La documentation en ligne d'Oracle fournit des informations sur Java SE 7.

Sur java - la page du lanceur d'applications Java pour Windows, l' -clientoption est ignorée dans un JDK 64 bits:

Sélectionnez la machine virtuelle client Java HotSpot. Un jdk compatible 64 bits ignore actuellement cette option et utilise à la place la machine virtuelle Java HotSpot Server.

Cependant (pour rendre les choses intéressantes), -serveril indique:

Sélectionnez la machine virtuelle Java HotSpot Server. Sur un jdk compatible 64 bits, seule la machine virtuelle Java HotSpot Server est prise en charge, de sorte que l'option -server est implicite. Ceci est susceptible de changer dans une future version.

La page Détection de machine de classe serveur fournit des informations sur la machine virtuelle sélectionnée par le système d'exploitation et l'architecture.

Je ne sais pas dans quelle mesure cela s'applique au JDK 6.

pharsicle
la source
2
Merci, je me demandais pourquoi je n'ai pas vu un client / jvm.dll sur JDK7
Archimedes Trajano
16

De Goetz - La concurrence Java en pratique:

  1. Conseil de débogage: pour les applications serveur, veillez à toujours spécifier le -servercommutateur de ligne de commande JVM lors de l'appel de la JVM, même pour le développement et les tests . La JVM du serveur effectue plus d'optimisation que la JVM du client, par exemple en sortant des variables d'une boucle qui ne sont pas modifiées dans la boucle; le code qui peut sembler fonctionner dans l'environnement de développement (JVM client) peut se briser dans l'environnement de déploiement (JVM serveur). Par exemple, si nous avions «oublié» de déclarer la variable endormie comme volatile dans le Listing 3.4, la JVM serveur pourrait hisser le test hors de la boucle (en le transformant en boucle infinie), mais pas la JVM client . Une boucle infinie qui apparaît en cours de développement est beaucoup moins coûteuse qu'une boucle qui apparaît uniquement en production.

Listing 3.4. Compter les moutons.

volatile boolean asleep; ... while (!asleep) countSomeSheep();

Mon accent. YMMV

Adam
la source
15

IIRC la VM du serveur fait plus d'optimisations de hotspot au démarrage afin qu'elle s'exécute plus rapidement mais prend un peu plus de temps pour démarrer et utilise plus de mémoire. La machine virtuelle cliente reporte la plupart de l'optimisation pour permettre un démarrage plus rapide.

Modifier pour ajouter: Voici quelques informations de Sun, ce n'est pas très spécifique mais vous donnera quelques idées.

Mike Akers
la source
5

IIRC, il implique des stratégies de collecte des ordures. La théorie est qu'un client et un serveur seront différents en termes d'objets de courte durée de vie, ce qui est important pour les algorithmes GC modernes.

Voici un lien sur le mode serveur. Hélas, ils ne mentionnent pas le mode client.

Voici un lien très complet sur GC en général; c'est un article plus basique . Je ne sais pas si l'adresse -server vs -client mais c'est du matériel pertinent.

Chez No Fluff Just Stuff, Ken Sipe et Glenn Vandenburg discutent très bien de ce genre de choses.

Michael Easter
la source
3

Je n'ai pas remarqué de différence de temps de démarrage entre les 2, mais j'ai enregistré une amélioration très minime des performances des applications avec "-server" (serveur Solaris, tout le monde utilise SunRays pour exécuter l'application). C'était moins de 1,5.

Brian Knoblauch
la source
6
Cela dépend de ce que fait votre programme. Pour certaines applications gourmandes en processeur qui font la même chose de façon répétée, j'ai remarqué des améliorations énormes (jusqu'à 10x) avec -server.
Dan Dyer
1
Dan, avez-vous une référence à cela? J'aimerais approfondir.
Thorbjørn Ravn Andersen
1
L'exécution de Sunflow avec la machine virtuelle du serveur est BEAUCOUP plus rapide que le client. sunflow.sourceforge.net
John
1

La dernière fois que j'ai jeté un œil à cela, (et il est vrai que c'était il y a quelque temps), la plus grande différence que j'ai remarquée était dans la collecte des ordures.

IIRC:

  • La machine virtuelle du tas de serveur a un nombre de générations différent de la machine virtuelle cliente et un algorithme de récupération de place différent. Ce n'est peut-être plus vrai
  • La machine virtuelle du serveur allouera de la mémoire et ne la libérera pas sur le système d'exploitation
  • La machine virtuelle du serveur utilisera des algorithmes d'optimisation plus sophistiqués, et aura donc des besoins en temps et en mémoire plus importants pour l'optimisation

Si vous pouvez comparer deux machines virtuelles Java, un client et un serveur à l'aide de l' outil jvisualvm , vous devriez voir une différence dans la fréquence et l'effet de la récupération de place, ainsi que dans le nombre de générations.

J'avais une paire de captures d'écran qui montraient très bien la différence, mais je ne peux pas reproduire car j'ai une JVM 64 bits qui implémente uniquement la machine virtuelle du serveur. (Et je ne peux pas être dérangé pour télécharger et démêler la version 32 bits sur mon système également.)

Cela ne semble plus être le cas, après avoir essayé d'exécuter du code sur des fenêtres avec des machines virtuelles serveur et client, il semble que j'obtienne le même modèle de génération pour les deux ...

brice
la source
1

Lors de la migration de la version 1.4 vers la version 1.7 ("1.7.0_55"). Ce que nous avons observé ici, il n'y a pas de telles différences dans les valeurs par défaut affectées aux paramètres heapsize | permsize | ThreadStackSize en mode client et serveur.

À propos, ( http://www.oracle.com/technetwork/java/ergo5-140223.html ). Il s'agit de l'extrait extrait du lien ci-dessus.

initial heap size of 1/64 of physical memory up to 1Gbyte
maximum heap size of ¼ of physical memory up to 1Gbyte

ThreadStackSize est plus élevé en 1.7, tandis que lors du forum Open JDK, il y a des discussions qui ont déclaré que la taille du cadre était un peu plus élevée dans la version 1.7. On pense qu'une réelle différence pourrait être possible de mesurer au moment de l'exécution en fonction de votre comportement de votre application

Nuwan Arambage
la source