Modificador static nos metodos, codigo mais rapido?

Hola joaosiqueira

Minha opinião sobre o tema:

  1. Alta performance e baixo uso de memória em sistemas OO sempre foi uma questão difícil de resolver vamos dizer assim.

  2. O uso mínimo ou nenhum uso de statics é uma caracteristica de bons designs.

Indo mais direto ao ponto: O código sendo estatico ou não ele tem que estar em um trecho da memória da máquina, como o sistema operacional + JVM não são bobos eles mantem estes trechos de código registrado na memória o máximo possível (provavemente seguindo alguma regra baseado no uso). Se tanto o código estatico e o não estático se encontram na mesma condição, vamos dizer assim, resta uma coisa que vou chamar de “code pointer” que aponta para o local da memória onde está o início do trecho de código que será processado; para este mecanismo não importa se o código é estatico ou não o processador verifica o endereço, desloca, processa e pronto.

Resumindo: A questão de ser static está mais associado com estrategia do que com performance, alguns programadores utilizam static ao definir constantes; pois se é uma constante eles não encontram muito sentido deixar o valor ser criado em todas as instancias da classe.

flws.

[quote=joaosiqueira][quote=davidtiagoconceicao]
What code shapes does the JVM optimize best? Here is a list.
Methods

Isto ainda nao responde as duvidas, pois vejo no artigo:

It’s OK to store them in static final fields, too.
Static final fields can hold non-primitive, non-string constants.
Static, private, final, and/or “special” invocations are easy to inline.

Portanto static sao muito mais rapidas… como se prova! Nao existem razoes para nao quererem usar, vejo o contrario indicaçoes recomendando da propria JVM!![/quote]

Este trecho cita também métodos private e final. E não prova nada, só diz que é mais fácil de otimizar. No máximo, será mais rápido para compilar - não é possível se basear nisso em tempo de execução.

No mais, acredito que procurar “otimizações” para uso do static seja apenas querer argumentar a favor de um design mal projetado: nada contra o uso dele, mas existem casos e casos.

Se vc pensar que todas variaveis membro declarados como static ficam carregas ate vc derrubar a VM, indica q existe um tipo de “cache estatico” na memoria, nao e?

Por isso, partindo desta ideia teriamos uma acelaraçao para os metodos static.
Nao estou considerando design e melhores praticas de refatoraçao.

Pensemos somente em velocidade de execuçao para um código!!

abrs

[quote=joaosiqueira]
Se vc pensar que todas variaveis membro declarados como static ficam carregas ate vc derrubar a VM, indica q existe um tipo de “cache estatico” na memoria, nao e?

Por isso, partindo desta ideia teriamos uma acelaraçao para os metodos static.
Nao estou considerando design e melhores praticas de refatoraçao.

Pensemos somente em velocidade de execuçao para um código!!

abrs[/quote]

Mas se você criar um objeto e passar ele pelo seu programa, ele também fica em memória… No final, todo o ‘custo adicional’ seria relacionado à criação do objeto.

E não entendi como você chegou a conclusão de que um método static pode ser mais rápido se as variáveis static ficam em cache…

Uma dúvida:
Se for criado X>1 objetos do tipo T,
cada objeto T com um método M (não estático),
serão criados X códigos para os métodos dps X objetos? Ou será criado apenas um código na memória e compartilhado entre os objetos?
(por favor, respondam com certeza)

Olha, na maioria das JVMs comerciais (todas, eu acho), cada objeto corresponde a uma área de memória. No offset 0 está a referência ao objeto Class correspondente (aquilo que é retornado pelo Object.getClass()), e os demais espaços da área de memória do objeto contém os atributos, um após o outro.

Existem quatro tipos de bytecodes de chamada de métodos: invokestatic, invokevirtual, invokeinterface e invokespecial. Há propostas para que no java 7 apareça o invokedynamic.

De uma forma simples*, podemos dizer que o invokestatic recebe como parâmetro um ponteiro para um objeto Class, um ID de um método estático e um monte de tipos primitivos e ponteiros de Objects que são os parâmetros. Então a JVM vai lá no objeto Class, procura o método ESTÁTICO correspondente ao ID e o invoca passando-lhe os parâmetros.

O invokevirtual e o invokeinterface recebem como parâmetro um ponteiro de um objeto que é a instância em que o método é invocado, um ID de um método não-estático e os parâmetros. A JVM verifica se o ponteiro da instância é nula e lança NullPointerException se for. Se não for, ela vai lá no endereço apontado pelo ponteiro da instância (que é onde está o objeto) e pega a classe deste (que está no offset 0, ou seja exatamente para onde o ponteiro aponta). Tendo então a classe, ela procura o método NÃO-ESTÁTICO correspondente ao ID e o invoca passando-lhe os parâmetros.

O invokespecial é para a chamada de construtores e se não me engano chamada de métodos sobrescritos da superclasse (não sei bem direito como isso funciona no nível dos bytecodes, mas isso não é relevante aqui neste tópico). O invokedynamic vamos deixar para quando sair o java 7.

Então, a estrutura do objeto não contém referências aos métodos. O objeto tem apenas um ponteiro para o objeto Class correspondente e os atributos um após o outro. A JVM usa o ponteiro para o objeto Class para localizar os métodos. Desta forma, objetos de uma mesma classe, ao apontar para o mesmo objeto Class usarão os mesmos métodos que estão no mesmo endereço de memória. Portanto, não há diferenças no uso da memória ou no desempenho** ao deixar um método como estático ou não-estático.

    • Simples, bem simples, para leigos entenderem.
      ** - Nunca vi nenhum benchmark de quanto tempo a JVM demora para empilhar os parâmetros para a chamada do método (incluindo o ID do método e a referência da instância do invokevirtual/invokeinterface), e nem quanto tempo ela demora para verificar se a referência da instância é nula ou não. Mas seja lá qual for este tempo, ele deve ser ínfimo e desprezível. Se você está tão desesperado por desempenho que isto pode lhe fazer diferença, então você nem devia estar programando em java, e sim em assembler (ou até no hardware).

EDITs: Correções de pequenos erros.

Boa explanação victorwss!

Completando o que o Victor disse.

Teoricamente, uma chamada “virtual” é um pouquinho* mais lenta que uma chamada não-virtual (e é por isso que o default do C# e do C++ - as chamadas são só “virtual” se forem explicitamente especificadas - é diferente do default do Java). Isso porque em vez de chamar o método diretamente, sem prestar atenção à classe do objeto, o Java deveria chamar o método indiretamente, por um ponteiro contido na definição da classe. Procure por “VTBL” na Internet.

Entretanto,
A JVM compensa esse fato de a chamada ser mais lenta efetuando uma pré-análise da chamada. Se for determinado em tempo de compilação just-in-time que a chamada não precisa ser “virtual” (ou seja, a variável contém um objeto de um determinado tipo apenas, em vez de ficar trocando de tipos que têm em comum apenas a mesma superclasse ou superinterface), então a JVM não faz a chamada virtual e sim a chamada direta (é como se ela determinasse que uma “invokevirtual” na verdade pudesse ser tão rápida quanto uma “invokespecial”).
Então não é necessário ficar especificando ou não “virtual” em Java, como é feito no C# ou no C++. Se vocês já programaram em alguma dessas linguagens, viram que na prática vocês acabam tendo de especificar sempre “virtual” para os métodos, para evitar alguns problemas esquisitos. Ou seja: veja o que o Java simplifica para vocês.

Por favor, me expliquem a diferença na memoria neste codigo static.
NAO adianta dizer q de uma forma eu crio uma instancia e na outra nao com o uso do new, pois penso q no final tudo se cria uma instancia internamente na VM. Pelo que li nos post acima, o desempenho seria igual nos 2, mas o q difere um do outro?

[code]class T{
static void show(){
System.out.println(“ddd”);
}
}

public class Lixo {

public static void main(String[] args) {
	T.show();
	new T().show();
}

}[/code]

Como o valor atribuido a um atributo static de uma clase pode manter um valor na memoria ate que a VM seja descarregada, onde esse valor e guardado pra que todas as classes possam ler o valor armazenado e compartilhado?

abrs

A chamada a um método estático de uma classe não envolve instanciar essa classe, apenas carregá-la. Portanto o que você disse está errado. Uma forma de você saber isso é criar um construtor e ver quantas vezes esse construtor é chamado: ele será chamado apenas 1 vez.

Resumidamente, o valor atribuído a um atributo static é referenciado pelo objeto do tipo java.lang.Class que representa essa classe. Internamente a JVM cria um objeto java.lang.Class para cada classe carregada (para cada classloader), e que contém uma lista dos atributos static dessa classe.

Então, os métodos podem ler o tal valor armazenado e compartilhado referindo-se a essa classe.

Thingol,

Isto de ser chamado 1 vez nao acontece… fiz ate o exemplo e veja:

[code]class T{
T(){
System.out.println(“T”);
}
static void show(){
System.out.println(“ddd”);
}
}

public class Lixo {

public static void main(String[] args) {
	T.show();
	T.show();
	
	new T().show();
	new T().show();
}

}[/code]

OutPut:
ddd
ddd
T
ddd
T
ddd

Cade essa unica vez q vc falou???

Se você chamou “new T” uma vez, então o construtor vai ser chamado 1 vez. Se você chamou 2 vezes (como é o seu caso), vai ser chamado 2 vezes. Eu é que não seu contar?

Thingol,

O que vc quiz dizer e que qdo eu uso o new passo pelo construtor, e qdo chamo o metodo static direto nao posso pelo construtor… certo???

Agora me explique, pra eu carregar uma classe eu nao preciso instanciala internamente? Nao entendo como posso carregar algo sem automaticamente instanciar, vejo como um processo sequencia… ? Mesmo que o construtor nao seja invocado, instanciar e uma forma de carregar…

Posso pensar que o T.show() e uma outra forma de instanciar uma classe na memoria sem passar por um construtor… tipo, a VM faz uma instancia diferenciada pro static…

Nao acha algo logico isso? :slight_smile:

Carregar uma classe (ou seja, carregar o código do arquivo .class ou .jar para poder chamar algum de seus métodos) é diferente de instanciar essa classe (ou seja, criar um objeto que pertence a essa classe.)

As palavras são diferentes (carregar X instanciar), porque o que é feito em cada caso é diferente.

Thingol,

Entao podemos dizer que qdo eu faço uma Reflection de uma classe, estou carregando da mesma forma que um static faz?

Se eu pensar neste modelo, sempre que dizer que um Reflection e mais lento do que dar um new, certo?? Teria que dizer que o static e mais lento tb, nao e?

O que vc acha disso?
:twisted:

[quote=joaosiqueira]Thingol,

Entao podemos dizer que qdo eu faço uma Reflection de uma classe, estou carregando da mesma forma que um static faz?

Se eu pensar neste modelo, sempre que dizer que um Reflection e mais lento do que dar um new, certo?? Teria que dizer que o static e mais lento tb, nao e?

O que vc acha disso?
:twisted: [/quote]

Impressão minha ou esse cara escreve feito o Márcio Duran?

Mauricio Linhares,

Por favor, so responda a minha pegunta! Pois e uma questao de logica de associaçao…
Afinal e educaçao respeitar a opiniao do outros.

abrs

Peraí,

vc entende o significado de new T().show() abaixo?

[code]class T{
static void show(){
System.out.println(“ddd”);
}
}

public class Lixo {

public static void main(String[] args) {
	T.show();
	new T().show();
}

}[/code]

Como o pessoal falou, os atributos estáticos pertencem à java.lang.Class. Quando você tem um método estático, mesmo que você dê new, o método não é aplicado ao objeto que vc criou, mas sim à classe da instância.

Então, dizer que existe diferença entre T.show() e new T().show() é absurdo, ambas são exatamente a mesma coisa! A única diferença é que no segundo exemplo, você simplesmente cria uma instância e a joga imediatamente.

Minha impressão é que você não entende muito de orientação a objetos, acredito que você precise dar uma estudada sobre isso.

Ola pessoal,

Uma duvida:

O processo que o modificador static faz nao e a mesma ideia que uma Reflection ?
Sempre que dizemos que um Reflection e mais lento do que dar um new, certo??

Portanto teria que dizer que o static e mais lento tb que fazer uma instanciaçao, nao e?

Qual o opiniao de vcs nisso?

abrs :slight_smile: