java jvm jvm-hotspot

¿Diferencias reales entre “java-server” y “java-client”?



jvm jvm-hotspot (11)

¿Hay alguna diferencia práctica real entre "java -server" y "java -client"? Todo lo que puedo encontrar en el sitio de Sun es un vago "el servidor comienza más lento pero debería funcionar más rápido". ¿Cuáles son las diferencias reales? (Usando JDK 1.6.0_07 actualmente).


Cuando se realiza una migración de la versión 1.4 a 1.7 ("1.7.0_55"). Lo que observamos aquí es que no hay diferencias en los valores predeterminados asignados a los parámetros de ThreadStackSize de heapsize | permsize en modo cliente y servidor.

Por cierto, ( http://www.oracle.com/technetwork/java/ergo5-140223.html ). Este es el fragmento tomado del enlace de arriba.

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

ThreadStackSize es mayor en 1.7, mientras que en el foro Open JDK, hay discusiones en las que se indica que el tamaño del marco es algo mayor en la versión 1.7. Se cree que la diferencia real podría ser posible medir en tiempo de ejecución según el comportamiento de su aplicación


Desde Goetz - Java concurrencia en la práctica:

  1. Consejo de depuración: para aplicaciones de servidor, asegúrese de especificar siempre el conmutador de línea de comandos de -servidor JVM al invocar el JVM, incluso para desarrollo y pruebas . La JVM del servidor realiza más optimización que la JVM del cliente, como levantar variables fuera de un bucle que no se modifican en el bucle; El código que puede parecer que funciona en el entorno de desarrollo (cliente JVM) puede interrumpirse en el entorno de implementación (servidor JVM). Por ejemplo, si hubiéramos "olvidado" declarar la variable como inactiva en el Listado 3.4, la JVM del servidor podría sacar la prueba del bucle (convirtiéndola en un bucle infinito), pero la JVM del cliente no lo haría . Un bucle infinito que aparece en el desarrollo es mucho menos costoso que uno que solo aparece en la producción.

Listado 3.4. Contando ovejas.

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

Mi énfasis. YMMV


Esto está realmente vinculado a HotSpot y los valores de opción predeterminados ( Opciones de Java HotSpot VM ) que difieren entre la configuración del cliente y el servidor.

Del Capítulo 2 del documento técnico ( La arquitectura de Java HotSpot Performance Engine ):

El JDK incluye dos tipos de VM: una oferta del lado del cliente y una VM sintonizada para aplicaciones de servidor. Estas dos soluciones comparten la base de código del entorno de tiempo de ejecución Java HotSpot, pero utilizan diferentes compiladores que se adaptan a las características de rendimiento distintivas y únicas de clientes y servidores. Estas diferencias incluyen la compilación en línea política y valores predeterminados de montón.

Aunque las máquinas virtuales de servidor y cliente son similares, la máquina virtual de servidor ha sido especialmente adaptada para maximizar la velocidad máxima de operación. Está diseñado para ejecutar aplicaciones de servidor de larga ejecución, que necesitan la velocidad de operación más rápida posible más que un tiempo de inicio rápido o una huella de memoria de tiempo de ejecución más pequeña.

El compilador Client VM sirve como una actualización para los compiladores Classic VM y just-in-time (JIT) utilizados por versiones anteriores de JDK. El cliente VM ofrece un rendimiento mejorado del tiempo de ejecución para aplicaciones y applets. La máquina virtual Java HotSpot Client se ha optimizado especialmente para reducir el tiempo de inicio de la aplicación y la huella de memoria, lo que lo hace especialmente adecuado para entornos de clientes. En general, el sistema cliente es mejor para las GUIs.

Así que la diferencia real también está en el nivel del compilador:

El compilador de VM de cliente no intenta ejecutar muchas de las optimizaciones más complejas realizadas por el compilador en la VM de servidor, pero a cambio, requiere menos tiempo para analizar y compilar un fragmento de código. Esto significa que la VM cliente puede iniciarse más rápido y requiere un menor espacio de memoria.

La VM del servidor contiene un compilador adaptativo avanzado que admite muchos de los mismos tipos de optimizaciones que se realizan al optimizar los compiladores de C ++, así como algunas optimizaciones que los compiladores tradicionales no pueden realizar, como la integración agresiva en todas las invocaciones de métodos virtuales. Esta es una ventaja competitiva y de rendimiento sobre los compiladores estáticos. La tecnología de optimización adaptativa es muy flexible en su enfoque, y generalmente supera incluso el análisis estático avanzado y las técnicas de compilación.

Nota: El lanzamiento de la actualización 10 de jdk6 (ver Notas de la versión de actualización: Cambios en 1.6.0_10 ) intentó mejorar el tiempo de inicio, pero por una razón diferente a las opciones del punto de acceso, se empaquetó de forma diferente con un kernel mucho más pequeño.

G. Demecki señala en los comentarios que en las versiones de JDK de 64 bits, la opción -client se ignora durante muchos años.
Ver el comando java Windows :

-client

Selecciona la Java VM HotSpot Client.
Un JDK con capacidad para 64 bits actualmente ignora esta opción y en su lugar utiliza la máquina virtual Java Hotspot Server .


IIRC, involucra estrategias de recolección de basura. La teoría es que un cliente y un servidor serán diferentes en términos de objetos de corta duración, lo que es importante para los algoritmos modernos de GC.

Aquí hay un enlace en modo servidor. Por desgracia, no mencionan el modo de cliente.

Aquí hay un enlace muy completo sobre GC en general; Este es un artículo más básico . No estoy seguro si la dirección -server vs -client pero este es material relevante.

En No Fluff Just Stuff, tanto Ken Sipe como Glenn Vandenburg hacen grandes conversaciones sobre este tipo de cosas.


IIRC, la máquina virtual del servidor, realiza más optimizaciones de puntos de acceso al inicio, por lo que se ejecuta más rápido, pero demora un poco más en iniciarse y utiliza más memoria. La máquina virtual del cliente difiere la mayor parte de la optimización para permitir un inicio más rápido.

Editar para agregar: Aquí hay información de Sun, no es muy específica pero le dará algunas ideas.


La última vez que eché un vistazo a esto (y hay que reconocer que fue hace un tiempo), la mayor diferencia que noté fue en la recolección de basura.

IIRC:

  • La VM del montón del servidor tiene un número diferente de generaciones que la VM del cliente y un algoritmo de recolección de basura diferente. Esto puede no ser más cierto
  • La máquina virtual del servidor asignará memoria y no la liberará al sistema operativo
  • La VM del servidor utilizará algoritmos de optimización más sofisticados y, por lo tanto, tendrá mayores requisitos de tiempo y memoria para la optimización

Si puede comparar dos máquinas virtuales de Java, un cliente, un servidor con la herramienta jvisualvm , debería ver una diferencia en la frecuencia y el efecto de la recolección de basura, así como en el número de generaciones.

Tuve un par de capturas de pantalla que mostraron la diferencia realmente bien, pero no puedo reproducir ya que tengo una JVM de 64 bits que solo implementa la VM del servidor. (Y no puedo molestarme en descargar y disputar la versión de 32 bits en mi sistema también).

Parece que este ya no es el caso, después de haber intentado ejecutar algún código en Windows con máquinas virtuales de servidor y cliente, parece que obtengo el mismo modelo de generación para ambos ...


La diferencia inmediata más visible en versiones anteriores de Java sería la memoria asignada a un -client en lugar de una aplicación de -server . Por ejemplo, en mi sistema Linux, obtengo:

$ 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"

como por defecto es -server , pero con la opción -client obtengo:

$ 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"

por lo tanto, con -server mayoría de los límites de memoria y las asignaciones iniciales son mucho más altas para esta versión java .

Sin embargo, estos valores pueden cambiar para diferentes combinaciones de arquitectura, sistema operativo y versión jvm. Las versiones recientes de jvm han eliminado las marcas y han eliminado muchas de las distinciones entre el servidor y el cliente.

Recuerde también que puede ver todos los detalles de un jvm ejecución usando jvisualvm . Esto es útil si tiene usuarios que o módulos que configuran JAVA_OPTS o usan scripts que cambian las opciones de la línea de comandos. Esto también le permitirá monitorear, en tiempo real, el uso del espacio de almacenamiento dinámico y permanente , junto con muchas otras estadísticas.


La documentación en línea de Oracle proporciona información para Java SE 7.

En java: la página de inicio de la aplicación Java para Windows, la opción -client se ignora en un JDK de 64 bits:

Seleccione la máquina virtual Java HotSpot Client. Un jdk con capacidad para 64 bits actualmente ignora esta opción y en su lugar utiliza la máquina virtual Java HotSpot Server.

Sin embargo (para hacer las cosas interesantes), debajo de -server dice:

Seleccione la máquina virtual Java HotSpot Server. En un jdk con capacidad para 64 bits, solo se admite la Java HotSpot Server VM, por lo que la opción -servidor es implícita. Esto está sujeto a cambios en una versión futura.

La página Detección de máquinas de clase de servidor proporciona información sobre qué VM está seleccionada por el sistema operativo y la arquitectura.

No sé cuánto de esto se aplica a JDK 6.


Los sistemas -client y -server son binarios diferentes. Son esencialmente dos compiladores diferentes (JIT) que interactúan con el mismo sistema de tiempo de ejecución. El sistema cliente es óptimo para aplicaciones que necesitan tiempos de inicio rápidos o pequeñas huellas, el sistema de servidor es óptimo para aplicaciones donde el rendimiento general es más importante. En general, el sistema cliente es más adecuado para aplicaciones interactivas como las GUI

Ejecutamos el siguiente código con ambos interruptores:

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--) { } } }

Nota: ¡ El código se ha compilado una sola vez! ¡Las clases son iguales en ambas carreras!

Con -cliente:
java.exe -client -classpath C: / mywork / classes com.blogspot.sdoulger.LoopTest
Tiempo empleado: 766.

Con -servidor:
java.exe -server -classpath C: / mywork / classes com.blogspot.sdoulger.LoopTest
Tiempo empleado: 0

¡Parece que la optimización más agresiva del sistema del servidor, elimina el bucle ya que entiende que no realiza ninguna acción!

Reference


No he notado ninguna diferencia en el tiempo de inicio entre los 2, pero registró una mejora mínima en el rendimiento de la aplicación con "-server" (servidor Solaris, todos los que usan SunRays para ejecutar la aplicación). Eso fue menos de 1.5.


Una diferencia que acabo de notar es que en el modo "cliente", parece que la JVM en realidad devuelve algo de memoria no utilizada al sistema operativo, mientras que con el modo "servidor", una vez que la JVM toma la memoria, no la dará. atrás. Así es como aparece en Solaris con Java6 de todos modos (usando prstat -Z para ver la cantidad de memoria asignada a un proceso).