sábado, 30 de maio de 2009

Java6u14: EA e LE

Sem fazer nenhum alarde (e uma semana antes do JavaOne 2009) a Sun resolveu lançar mais uma atualização para o JRE6 - o Update 14. Devido às indefinições sobre o Java7 (que ainda não possui uma JSR), a Sun tem feito, em suas atualizações do Java6, grandes modificações, entre as quais o "novo plugin" no update 10, capacidade de atualização "in place" para windows no update 11, o plugin de 64 bits no update 12 e - o principal assunto deste artigo - análise de escape e o novo garbage collector (G1) no update 14.


Escape Analysis
A análise de escape permite à JVM detectar quando um objeto é "não escapante" (ou seja, seu ciclo de vida está confinado a um escopo local). Quando um objeto desse tipo é detectado, o JIT vai (supostamente) alocá-lo na pilha (ao invés do heap) e tratar seus campos como variáveis locais e, no melhor caso, trabalhar apenas com os registradores do seu CPU. Além disso, é garantidamente seguro ignorar os monitores destes objetos - uma otimização conhecida como "lock elision".

Um pouco de história:
Na época do desenvolvimento do Java6, a análise de escape estava prometida como um dos responsáveis por um aumento de performance sobre o Java5. Algumas JVMs da época já tinham essa feature (ou pelo menos em teoria, de acordo com este artigo), mas devido ao tempo escasso, a JVM6 era capaz de fazer a análise, mas não implementava nenhuma otimização com essas informações.

Na prática...
Vamos ver como a EA (escape analysis) e LE (lock elision) se saem em alguns microbenchmarks simples.
O primeiro teste consiste em alocar um objeto simples, com dois campos, dentro de um for, alterar o valor dos seus campos, e somá-los. Estas operações são feitas através de métodos ao inves de acessar os campos diretamente, com a análise de escape desligada primeiro, depois ligada.
Antes de mais nada, a EA só pode ser ativada na jvm server (ou seja, está presente apenas na JDK6U14 e não na JRE6U14) e com uma opção não padrão (daquelas que começam com -XX)
-XX:+DoEscapeAnalysis

A parte principal do código:


public void execute() {
for (int i = 0; i < max; i++) {
Foo foo = new Foo();
foo.setNumA(i);
foo.setNumB(i * i);
total += foo.sum();
}
}



Os resultados foram:

Tempo de execução para 1000000000 iterações
client vm: 11922 ms
server vm: 8452 ms
server vm + EA: 1611ms

Ou, em iterações por millisegundo:
client vm: 83872
server vm: 118306
server vm + EA: 620578

Como pode ser visto, usando a EA, o pequeno teste ficou mais de 6x mais rápido. Claro que estes números não devem ser lidos literalmente, pois este teste foi especificamente designado para tirar vantagem da análise - em outras palavras não espere esta melhoria no eclipse do dia-a-dia ou no jboss em produção.

Lock elision
Lock elision é uma das técnicas que poderia ser uma gigantesca vantagem das linguagens dinamicamente compiladas sobre as estaticamente compiladas. E o update 14 especificamente menciona que com a análise de escape ativada, os locks também seriam eliminados. Executando o mesmo teste, agora com todos os métodos marcados como sincronizados, temos:

Alterando o código anterior para:

public void execute() {
for (int i = 0; i < max; i++) {
SFoo foo = new SFoo();
foo.setNumA(i);
foo.setNumB(i * i);
total += foo.sum();
}
}

Onde SFoo é idêntico a Foo, porém com seus métodos marcados como synchronized.

Tempo de execução para 100000000 (perceba que eu tive que usar 10x menos operações para a versão sincronizada):
client vm: 6337 ms
server vm: 4184 ms
server vm + EA: 276 ms (!!!)

Ou, em iterações por millisegundo:
client vm: 15778
server vm: 23897
server vm + EA: 361271

Ou seja, o speedup aqui foi de 21x - bem melhor do que a versão não sincronizada. Este resultado sugere que o lock elision é, de alguma forma feito. Porém, se compararmos somente os resultados da EA, a versão sincronizada é quase 2x mais lenta, o que sugere que a JIT não elimina todo o overhead da entrada e saída do monitor - quem sabe para continuar com algumas garantias de visibilidade.

Já se alterarmos o código inicial para:

public void execute() {
for (int i = 0; i < max; i++) {
Foo foo = new Foo();
synchronized (foo) {
foo.setNumA(i);
foo.setNumB(i * i);
total += foo.sum();
}
}
}

Seria esperado que os resultados fossem parecidos com o primeiro caso, já que o monitor do objeto foo só é adquirido uma vez por iteração. Vamos aos resultados (dessa vez apenas com o EA ativado), desta vez combinado com outras opções presentes antes do update 14 que poderiam afetar este teste:

Tempo em millisegundos para 1000000000 iterações:
server + EA: 9606ms
server + EA + Eliminate locks: 9543ms
server + EA + Biased locking: 9599ms
server + todas acima: 9515ms

As opções acima (Eliminate Locks e Biased Locking) são ativadas respectivamente por: -XX:+EliminateLocks e -XX:+UseBiasedLocking e, supostamente, são ativadas por padrão.
Aparentemente, um bloco sincronizado maior limita as otimizações que podem ser feitas pela análise de escape - os resultados obtidos estão aproximadamente 3x piores do que o teste anterior (com os métodos marcados com 'synchronized').

G1 e "Compressed OOPTS"
Além da EA, o update 14 trouxe também um novo garbage collector chamado G1 (garbage first), apresentado no JavaOne 2008 e ainda em estágio experimental. Trata-se de um GC paralelo e que tenta garantir uma pausa máxima (que pode ser definida pela linha de comando) e pode ser ativada pela combinação de opções:
-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
Por último, os "compressed object pointers" também foram integrados. Quem usa uma jvm de 64bits já deve ter notado que o consumo de memória é bem maior do que na jvm de 32 bits. Isso ocorre porque as referências para objetos ocupam 64 bits, mesmo quando todo o espaço de endereçamento não é necessário. Com esta opção nas JVM de 64 bits, as referências para objetos continuam com 32 bits a menos que seja necessário. Esta opção é ativada por:

-XX:+UseCompressedOops


e já existia nas JVM de "performance".


Mais informações sobre o G1 podem ser encontradas em:

e uma pequena demonstração dos ponteiros comprimidos pode ser vista em:
(ainda na jvm6 de performance)

Conclusão
Estas últimas atualizações podem trazer ganhos de performance muito bons para alguns cenários, embora haja alguma limitação no que a JVM pode fazer na presença de locks - o que pode muito bem ser corrigido em updates futuros ou quem sabe no jdk7. Embora eu espere que o JDK7 não demore a sair, acho muito interessante que a Sun não esteja se contendo em aperfeiçoar a sua JVM mesmo nas atualizações menores.







public static void main(String[] args) {
//yey
/**
* woot
*/
}

terça-feira, 26 de maio de 2009

Falando em Java

Olá,

sejam bem vindos ao Blog da Maps. Este primeiro post irá falar do evento "Falando em Java" organizado pela Caelum neste último domingo 24 de maio de 2009.

Este ano os palestrantes internacionais convidados foram Jim Webber da Thoughtworks e Bill Burke da Red Hat. Este último no entanto não conseguiu ir ao evento por problemas com seu visto para o Brasil. Sua palestra foi substituida por uma palestra adicional de Jim Webber. Seguem minhas impressões:

"Keynote: Guerrilha SOA" por Jim Webber

Boa apresentação. O palestrante demonstrou um ótimo preparo e muito conhecimento sobre o tema discutido. Jim contou rapidamente como a computação vem encarando o problema da integração entre softwares para então criticar o modelo atual. Segundo ele, este modelo não escala muito bem ou não se adequa muito bem por depender de middlewares que realizem a comunicação. O modelo que ele propõe faz uso da própria Web como middleware através de operações REST. REST propõe que funcionalidades da aplicação sejam abstraídas em "recursos" únicos (por exemplo uma URI) e que o acesso a estes recursos seja feito por meio de uma interface padronizada (por exemplo HTTP) e que desta forma sejam transportados representações destes recursos (html, json, xml, etc). Jim defende que a própria Web atende todos estes requisitos além de prover "methods" (GET, POST, PUT, DELETE) que ajudam a identificar as operações (ou serviços) que queremos executar. Neste modelo não é necessário nenhum tipo de middleware para realizar a comunicação entre aplicações, apenas a capacidade de disparar um request com determinado método para determinada URI e a capacidade de entender a resposta. Para quem quiser saber mais sobre isso segue o link da wiki: http://en.wikipedia.org/wiki/Representational_State_Transfer .

"O profissional Java efetivo" por Paulo Silveira e Rafael Cosentino

Apresentação inconsistente. O tema parecia muito interessante porém a palestra foi mal conduzida. Os palestrantes não demonstraram preparo. Adotaram um modelo de apresentação baseado em piadas (internas, sem a menor graça) e perderam muito tempo com isso. Abstraindo a questão das piadas, os palestrantes se concentraram um demonstrar diversos problemas de integração entre softwares e qual era a maneira mais adequada de resolver cada um dados os requisitos da comunicação a ser estabelecida. Por exemplo, para uma integração semanal entre assistências técnicas e uma matriz sugeriram CSV pela simplicidade. Para um médico controlar remotamente um robô que está realizando uma operação em tempo real sugeriram um protocolo binário pela performance. Para "mashup's" (http://en.wikipedia.org/wiki/Mashup_(web_application_hybrid)) foram sugeridos web services. Por terem se concentrado nas piadas acabaram não aprofundando nenhum dos exemplos apenas listando os prós e contras de cada solução adotada. Foi apenas no final da palestra que o Paulo conseguiu fazer alguns comentários alinhados com o título da palestra. Ele sugeriu (com razão) que profissionais Java devem continuar estudando sobre programação em geral, se envolver com a comunidade, ler blogs técnicos, etc. Concordo plenamente, inclusive a recomendação é válida para qualquer tipo de profissional. Hoje em dia as coisas mudam de figura muito rápido, o que hoje está em alta rapidamente pode estar em baixa. Para não ficarmos para trás temos que nos manter atualizados.

"JBoss Seam e WebBeans" por Alessandro Lazarotti e Ricardo Nakamura

Apresentação regular. Começaram com uma metáfora para explicar inversão de controle / injeção de dependências. Embora a metáfora tenha sido boa (um contraste entre ir até a padaria comprar o pão e receber o pão em casa) acabaram perdendo tempo com demasiadas tentativas de humor (uma ou outra boa). Na sequência, mostraram como resolver o problema usando anotações do WebBeans. Explicaram rapidamente que WebBeans é a implementação de referência da JSR-299 que se propõe a padronizar a forma como injeção de dependências deve ser feita em Java. Em seguida mostraram uma demo que funcionou corretamente. Acabaram pouco de Seam, apenas disseram que o core do Seam em sua próxima versão será o WebBeans e mostraram algumas features adicionais. No geral a apresentação foi melhor que a anterior embora tenham mal aproveitado o tempo.

"VRaptor 3: Guerrilha Web" por Felipe Sabella e Guilherme Silveira

Infelizmente voltamos do almoço apenas a tempo de pegar o final da palestra. A apresentação mostrou o VRaptor que está estreiando sua versão 3.0. O VRaptor é um framework MVC desenvolvido pelo pessoal da Caelum com foco em Ajax, rich interfaces, REST e integração com outros frameworks.

Arquitetura para aplicações Java de médio porte por Guilherma Moreira e Segio Lopes

Apresentação ruim. Novamente ficou clara a falta de preparo. Perderam tempo com encenações e as demos não funcionaram corretamente. Deram algumas dicas de Hibernate para resolução de problemas comuns:
- commit + clear para limpar o transaction log e o persistence context evitando um demasiado uso de memória e consequente diminuição de performance por conta de "garbage collection"
- uso de stateless session para inserts em massa

Para onde vai a plataforma Java? Linguagens dinâmicas, JavaTV, JavaFX e além! por Anderson Leite e Fabio Kung

Apresentação regular. Explicaram como são feitas chamadas a métodos no bytecode em diversos casos (invokestatic, invokespecial, invokevirtual e o novo invokedynamic que será introduzido no Java7). Depois disso abordaram funcionalidades encontradas em linguagens dinâmicas como Closures. Mostraram as propostas de inclusão de Closures em Java (BGGA, CICE e FCM) porém com péssimos exemplos que não demonstraram o real poder que este recurso permite. Do jeito que foi colocado pareceu que closures em Java seriam apenas um jeito mais bizarro de se escrever as mesmas coisas. Isto é péssimo pois quem não tinha tido contato com este tipo de construção antes ficou com uma impressão completamente equivocada. No fim, por terem perdido tempo nos tópicos anteriores não falaram de JavaTV e nem de JavaFX apenas citando rapidamente o Ginga-NCL e o GingaJ (http://www.ginga.org.br/).

GET /Connected por Jim Webber

Ótima apresentação. Após um dia inteiro de palestras regulares ou inconsistentes foi refrescante ter encerrado com mais uma boa palestra de Jim Webber. Novamente o palestrante demonstrou excelente preparo inclusive com improvisações muito bem encaixadas. Jim continuou falando de "Web Enabled Services" com REST. Seguiu defendendo a Web como o middleware perfeito para este cenário sem necessidade de outros frameworks realizarem a comunicação. Não chegou a dar um exemplo prático mas explicou com maiores detalhes como funcionariam por exemplo pedidos de café numa cafeteria qualquer usando REST, basicamente um case CRUD. Mostrou como seriam feitos a inserção, alteração e remoção do pedido e o que aconteceria em casos inválidos (por exemplo a tentativa de alteração de um pedido já preparado).

Para encerrar este longo primeiro post posso dizer que a ida ao evento valeu a pena, principalmente por conta das palestras do Jim Webber.