source - Diferenças reais entre “java-server” e “java-client”?
jvm open source (8)
Existe alguma diferença prática real entre "java -server" e "java -client"? Tudo o que posso encontrar no site da Sun é um vago "- o servidor começa mais devagar, mas deve ser executado mais rápido". Quais são as diferenças reais? (Usando o JDK 1.6.0_07 atualmente.)
https://code.i-harness.com
A última vez que eu dei uma olhada nisso (e admitidamente já faz um tempo) a maior diferença que notei foi na coleta de lixo.
IIRC:
- A VM do heap 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á para o 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, um servidor usando a ferramenta jvisualvm , deverá ver uma diferença na frequência e no 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, já que tenho uma JVM de 64 bits que implementa apenas a VM do servidor. (E eu não posso ser incomodado para baixar e disputar a versão de 32 bits no meu sistema também.)
Isso não parece mais ser o caso, tendo tentado executar algum código em janelas com VMs de servidor e cliente, parece que eu obtive o mesmo modelo de geração para ambos ...
A diferença imediata mais visível em versões mais antigas do Java seria a memória alocada a um -client
em oposição a um aplicativo -server
. 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 opção -client
eu 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"
Assim, com -server
maioria dos limites de memória e alocações iniciais são muito maiores para esta versão de java
.
Esses valores podem mudar para diferentes combinações de arquitetura, sistema operacional e versão jvm. Versões recentes do jvm removeram flags e removeram muitas das distinções entre servidor e cliente.
Lembre-se também que você pode ver todos os detalhes de um jvm
execução usando jvisualvm
. Isso é útil se você tiver usuários que ou módulos que definem JAVA_OPTS
ou usam scripts que alteram as opções da linha de comandos. Isso também permitirá que você monitore, em tempo real, o uso do espaço de heap e permgen junto com muitas outras estatísticas.
Ao fazer uma migração de 1.4 para 1.7 ("1.7.0_55") version.The coisa que observamos aqui é, não há tais diferenças nos valores padrão atribuídos aos parâmetros heapsize | permsize | ThreadStackSize no modo cliente e servidor.
By the way, ( http://www.oracle.com/technetwork/java/ergo5-140223.html ). Este é o trecho extraído 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
ThreadStackSize é maior em 1.7, enquanto passa pelo fórum Open JDK, existem discussões que afirmaram que o tamanho do frame é um pouco mais alto na versão 1.7. Acredita-se que a diferença real seja possível medir em tempo de execução com base no seu comportamento de sua aplicação
De Goetz - Java Concorrência na Prática:
- Dica de Depuração: Para aplicativos do servidor, certifique-se sempre de especificar a opção de linha de comandos JVM do servidor ao chamar a JVM, mesmo para desenvolvimento e teste . A JVM do servidor executa mais otimização do que a JVM do cliente, como a elevação de variáveis de um loop que não são modificadas no loop; código que pode parecer funcionar no ambiente de desenvolvimento (JVM do cliente) pode quebrar no ambiente de implementação (servidor JVM). Por exemplo, se tivéssemos “esquecido” de declarar a variável adormecida como volátil na Listagem 3.4, a JVM do servidor poderia elevar 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
IIRC a VM do servidor faz mais otimizações de hotspot na inicialização, portanto, ele é executado 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 fornecem algumas ideias.
IIRC, envolve estratégias de coleta de lixo. A teoria é que um cliente e um servidor serão diferentes em termos de objetos de curta duração, 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 muito completo sobre GC em geral; Este é um artigo mais básico . Não tenho certeza se qualquer um dos endereços -server vs -client, mas este é um material relevante.
No No Fluff Just Stuff, Ken Sipe e Glenn Vandenburg fazem grandes conversas sobre esse tipo de coisa.
Uma diferença que acabei de notar é que no modo "cliente", parece que a JVM realmente fornece alguma memória não utilizada de volta ao sistema operacional - ao passo que no modo "servidor", uma vez que a JVM agarra a memória, ela não dará de volta. Assim é como aparece no Solaris com o Java6 (usando prstat -Z para ver a quantidade de memória alocada para um processo).
os sistemas -client e -server são binários diferentes. Eles são essencialmente dois compiladores diferentes (JITs) interagindo com o mesmo sistema de tempo de execução. O sistema cliente é ideal para aplicações que precisam de tempos de inicialização rápidos ou pequenas áreas de ocupação, o sistema de servidor é ideal para aplicações em que o desempenho geral é mais importante. Em geral, o sistema cliente é mais adequado para aplicativos interativos, como GUIs
Nós executamos o seguinte código com os dois switches:
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 aulas são as mesmas nas duas corridas!
Com -client:
java.exe -client -classpath C: \ mywork \ classes com.blogspot.sdoulger.LoopTest
Tempo gasto: 766
Com -servidor:
java.exe -server -classpath C: \ mywork \ classes com.blogspot.sdoulger.LoopTest
Tempo gasto: 0
Parece que o optimazation mais agressivo do sistema do servidor, remova o loop, uma vez que entende que ele não executa qualquer ação!