Diferenças reais entre "servidor java" e "cliente java"?

394

Existe alguma diferença prática real entre "servidor java" e "cliente java"?

Tudo o que posso encontrar no site da Sun é um vago

"-server começa mais lento, mas deve correr mais rápido".

Quais são as diferenças reais? (Usando o JDK 1.6.0_07 atualmente.)

Paul Tomblin
fonte

Respostas:

368

Isso está realmente vinculado ao HotSpot e aos valores das opções padrão ( Java HotSpot VM Options ) que diferem entre a configuração do cliente e do servidor.

No capítulo 2 do whitepaper ( A arquitetura do Java HotSpot Performance Engine ):

O JDK inclui dois tipos de VM - uma oferta do lado do cliente e uma VM ajustada para aplicativos de servidor. Essas duas soluções compartilham a base de código do ambiente de tempo de execução do Java HotSpot, mas usam compiladores diferentes adequados às características de desempenho distintamente exclusivas de clientes e servidores. Essas diferenças incluem a diretiva de compilação e os padrões de heap.

Embora as VMs do servidor e do cliente sejam semelhantes, a VM do servidor foi ajustada especialmente para maximizar a velocidade operacional máxima. Ele se destina à execução de aplicativos de servidor de longa execução, que precisam da velocidade operacional mais rápida possível, mais do que um tempo de inicialização rápido ou menor espaço na memória de tempo de execução.

O compilador Client VM serve como um upgrade para os compiladores Classic VM e just-in-time (JIT) usados ​​pelas versões anteriores do JDK. A VM do cliente oferece desempenho aprimorado do tempo de execução para aplicativos e applets. A VM do cliente Java HotSpot foi ajustada especialmente para reduzir o tempo de inicialização do aplicativo e o espaço ocupado pela memória, tornando-o particularmente adequado para ambientes do cliente. Em geral, o sistema do cliente é melhor para GUIs.

Portanto, a diferença real também está no nível do compilador:

O compilador da VM do cliente não tenta executar muitas das otimizações mais complexas executadas pelo compilador na VM do servidor, mas, em troca, requer menos tempo para analisar e compilar um trecho de código. Isso significa que a VM do cliente pode ser inicializada mais rapidamente e requer um espaço menor de memória.

A VM do servidor contém um compilador adaptativo avançado que suporta muitos dos mesmos tipos de otimizações executadas pela otimização de compiladores C ++, além de algumas otimizações que não podem ser feitas pelos compiladores tradicionais, como o alinhamento agressivo através de invocações de métodos virtuais. Essa é uma vantagem competitiva e de desempenho sobre os compiladores estáticos. A tecnologia de otimização adaptativa é muito flexível em sua abordagem e geralmente supera até as técnicas avançadas de análise e compilação estáticas.

Nota: O lançamento da atualização 10 do jdk6 (consulte as Notas da versão de atualização: alterações em 1.6.0_10 ) tentou melhorar o tempo de inicialização, mas por um motivo diferente das opções do ponto de acesso, sendo empacotado de maneira diferente com um kernel muito menor.


G. Demecki ressalta nos comentários que nas versões de 64 bits do JDK, a -clientopção é ignorada por muitos anos.
Consulte o javacomando do Windows :

-client

Seleciona a VM Java HotSpot Client.
Um JDK com capacidade para 64 bits atualmente ignora essa opção e, em vez disso, usa a VM do Java Hotspot Server .

VonC
fonte
7
A atualização 10 do jdk6 e seguintes têm um processo em segundo plano, mantendo as bibliotecas de tempo de execução na memória, permitindo uma inicialização muito mais rápida para novos processos do que ter que paginar tudo sob demanda.
Thorbjørn Ravn Andersen
11
Pensei que o cliente vm também se destacou agressivamente, tudo bem.
Thorbjørn Ravn Andersen
11
Eu acho que essa resposta deve ser atualizada. Como nas versões de 64 bits do JDK, a -clientopção é ignorada por muitos anos.
G. Demecki 16/03
@ G.Demecki Claro: você tem um link documentando que esta opção é obsoleta ou ignorada?
VonC 16/03/19
11
Certo. Aqui está uma documentação para o Java 7 para Windows. E surpreendentemente, uma informação semelhante pode ser encontrada também na documentação do Java 6 .
G. Demecki 16/03/19
90

A diferença imediata mais visível nas versões mais antigas do Java seria a memória alocada a um -cliente não a um -serveraplicativo. Por exemplo, no meu sistema Linux, recebo:

$ 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 padrão -server, mas com a -clientopção que recebo:

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

portanto, com a -servermaioria dos limites de memória e alocações iniciais são muito maiores para esta javaversão.

Esses valores podem ser alterados para diferentes combinações de arquitetura, sistema operacional e versão da jvm. Versões recentes da jvm removeram sinalizadores e mudaram muitas das distinções entre servidor e cliente.

Lembre-se também de que você pode ver todos os detalhes de uma corrida jvmusando jvisualvm. Isso é útil se você tiver usuários que ou módulos que configuram JAVA_OPTSou usam scripts que alteram as opções da linha de comando. Isso também permitirá que você monitore, em tempo real, o uso de heap e permgen space, além de muitas outras estatísticas.

Mark Booth
fonte
2
Ele fornece os mesmos números nos modos -servidor e -cliente para a versão java "1.7.0_79" no CentOS 7 [Java (TM) SE Runtime Environment (compilação 1.7.0_79-b15) VM do servidor Java HotSpot (TM) de 64 bits ]
Basil Musa
4
É por isso que eu forneci a resposta. Não se trata dos valores, é permitir que qualquer pessoa, a qualquer momento, encontre a resposta para sua versão específica da jvm.
Mark Booth
33

os sistemas -client e -server são binários diferentes. Eles são essencialmente dois compiladores (JITs) diferentes que fazem interface com o mesmo sistema de tempo de execução. O sistema do cliente é ideal para aplicativos que precisam de tempos de inicialização rápidos ou pequenas pegadas, o sistema do servidor é ideal para aplicativos em que o desempenho geral é mais importante. Em geral, o sistema do cliente é mais adequado para aplicativos interativos, como GUIs

insira a descrição da imagem aqui

Executamos o seguinte código com os dois comutadores:

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: O código foi compilado apenas uma vez! As classes são as mesmas em ambas as execuções!

Com -client:
java.exe -client -classpath C: \ mywork \ classes com.blogspot.sdoulger.LoopTest
Tempo gasto: 766

Com -server:
java.exe -server -classpath C: \ mywork \ classes com.blogspot.sdoulger.LoopTest
Tempo gasto: 0

Parece que a otimização mais agressiva do sistema do servidor remove o loop, pois entende que ele não executa nenhuma ação!

Referência

Premraj
fonte
33

Uma diferença que acabei de notar é que, no modo "cliente", parece que a JVM realmente devolve alguma memória não utilizada ao sistema operacional, enquanto que no modo "servidor", uma vez que a JVM agarra a memória, ela não a fornece. de volta. É assim que aparece no Solaris com Java6 de qualquer maneira (usando prstat -Zpara ver a quantidade de memória alocada para um processo).

prule
fonte
22

A documentação online da Oracle fornece algumas informações para o Java SE 7.

Na página java - o iniciador de aplicativos Java para Windows, a -clientopção é ignorada em um JDK de 64 bits:

Selecione a VM do cliente Java HotSpot. Um jdk com capacidade para 64 bits atualmente ignora essa opção e, em vez disso, usa a VM do Java HotSpot Server.

No entanto (para tornar as coisas interessantes), segundo -serverele afirma:

Selecione a VM do Java HotSpot Server. Em um jdk com capacidade de 64 bits, apenas a VM do Java HotSpot Server é suportada, portanto a opção -server está implícita. Isso está sujeito a alterações em uma versão futura.

A página Detecção de máquinas de classe de servidor fornece informações sobre qual VM é selecionada pelo SO e pela arquitetura.

Não sei quanto disso se aplica ao JDK 6.

farículo
fonte
2
Obrigado, eu queria saber como é que eu não vi um client / jvm.dll no JDK7
Archimedes Trajano
16

De Goetz - Concorrência Java na Prática:

  1. Dica para depuração: Para aplicativos de servidor, sempre especifique a -serveropção da linha de comandos da JVM ao chamar a JVM, mesmo para desenvolvimento e teste . A JVM do servidor executa mais otimização que a JVM do cliente, como içar variáveis ​​de um loop que não são modificadas no loop; o código que pode parecer funcionar no ambiente de desenvolvimento (JVM do cliente) pode ser interrompido no ambiente de implementação (JVM do servidor). Por exemplo, se tivéssemos "esquecido" de declarar a variável adormecida como volátil na Listagem 3.4, a JVM do servidor poderia retirar o teste do loop (transformando-o em um loop infinito), mas a JVM do cliente não o faria . Um loop infinito que aparece no desenvolvimento é muito menos caro do que aquele que só aparece na produção.

Listagem 3.4. Contando ovelhas.

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

Minha ênfase. YMMV

Adão
fonte
15

IIRC, a VM do servidor faz mais otimizações de hotspot na inicialização, para que seja executada mais rapidamente, mas demora um pouco mais para iniciar e usa mais memória. A VM do cliente adia a maior parte da otimização para permitir uma inicialização mais rápida.

Editar para adicionar: aqui estão algumas informações da Sun, não são muito específicas, mas fornecerão algumas idéias.

Mike Akers
fonte
5

IIRC, envolve estratégias de coleta de lixo. A teoria é que um cliente e servidor serão diferentes em termos de objetos de vida curta, o que é importante para os algoritmos modernos de GC.

Aqui está um link no modo de servidor. Infelizmente, eles não mencionam o modo cliente.

Aqui está um link completo no GC em geral; este é um artigo mais básico . Não tenho certeza se o endereço -server vs -client, mas este é um material relevante.

No No Fluff Just Stuff, Ken Sipe e Glenn Vandenburg fazem ótimas conversas sobre esse tipo de coisa.

Michael Easter
fonte
3

Eu não notei nenhuma diferença no tempo de inicialização entre os 2, mas registrei uma melhoria muito mínima no desempenho do aplicativo com "-server" (servidor Solaris, todos usando SunRays para executar o aplicativo). Isso foi abaixo de 1,5.

Brian Knoblauch
fonte
6
Depende do que o seu programa está fazendo. Para alguns aplicativos com uso intensivo de processador que fazem a mesma coisa repetidamente, observei grandes melhorias (até 10x) com o -server.
Dan Dyer
11
Dan, você tem uma referência a isso? Eu gostaria de investigar mais.
Thorbjørn Ravn Andersen
11
A execução do Sunflow com a VM do servidor é MUITO mais rápida que o cliente. sunflow.sourceforge.net
John
1

A última vez que olhei para isso (e reconhecidamente faz um tempo) a maior diferença que notei foi na coleta de lixo.

IIRC:

  • A VM de pilha do servidor tem um número diferente de gerações que a VM do cliente e um algoritmo de coleta de lixo diferente. Isso pode não ser mais verdade
  • A VM do servidor alocará memória e não a liberará no sistema operacional
  • A VM do servidor usará algoritmos de otimização mais sofisticados e, portanto, terá maiores requisitos de tempo e memória para otimização

Se você puder comparar duas VMs java, um cliente e um servidor usando a ferramenta jvisualvm , verá uma diferença na frequência e efeito da coleta de lixo, bem como no número de gerações.

Eu tinha um par de capturas de tela que mostravam a diferença muito bem, mas não consigo reproduzir porque tenho uma JVM de 64 bits que apenas implementa a VM do servidor. (E não posso me incomodar em baixar e compor a versão de 32 bits no meu sistema também.)

Este não parece mais ser o caso, depois de tentar executar algum código no Windows com VMs de servidor e cliente, parece que obtive o mesmo modelo de geração para ambos ...

brice
fonte
1

Ao fazer uma migração da versão 1.4 para a 1.7 ("1.7.0_55"). O que observamos aqui é que não existem diferenças nos valores padrão atribuídos aos parâmetros heapsize | permsize | ThreadStackSize no modo cliente e servidor.

A propósito, ( http://www.oracle.com/technetwork/java/ergo5-140223.html ). Este é o trecho retirado do link acima.

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

O ThreadStackSize é maior na 1.7, enquanto no fórum Open JDK, há discussões que afirmam que o tamanho do quadro é um pouco maior na versão 1.7. Acredita-se que seja possível medir a diferença real no tempo de execução com base no seu comportamento do aplicativo

Nuwan Arambage
fonte