Olá Pessoal, tudo bom?
Semana passada nós falamos sobre a Method Area, que é uma subárea que está contida dentro da Runtime Data Area. Essa semana nós iremos descrever uma forma de utilização dessa subárea. Lembrando que esse artigo continuará a utilizar alguns conceitos sobre arquitetura de sistemas operacionais, assim termos desconhecidos podem surgir no contexto desse artigo. Peço nesses casos que me envie comentários a respeito desses termos, para que eu possa complementar o artigo e responder suas duvidas.
Method Area – Exemplo de Utilização
Nesse artigo iremos mostrar um exemplo de como subárea Method Area é utilizada pela JVM. Para tanto iremos definir duas classes, Lava e Vulcao, para melhor exemplificar essa utilização:
1 2 3 4 5 |
package br.com.mauda.arquitetura.methodArea; public class Lava { private int velocidadeKmPorHora = 5; } |
1 2 3 4 5 6 7 |
package br.com.mauda.arquitetura.methodArea; public class Vulcao { public static void main(String[] args) { Lava lava = new Lava(); } } |
Chamando o método main(String[])
O primeiro ponto para a JVM é a execução do método main(String[]) localizado dentro da classe Vulcao. Essa será a primeira instrução em byte codes a ser executada pela JVM. Lembrando que a forma de executar pode variar de acordo com a implementação da JVM, assim o processo a seguir ilustra uma forma de execução, mas não a única.
Para rodar a aplicação Vulcao, a JVM irá procurar, via Class Loader, o arquivo Vulcao.class. Dessa forma a informação contida nesse arquivo será extraída e inserida dentro da Method Area. A JVM irá então invocar o método main(String[]), interpretando os byte codes armazenados na Method Area. Ao executar o método main(), a JVM irá manter um ponteiro dentro da Constant Pool para a classe atual (Vulcao).
Note que a JVM já começou a executar os byte codes para o método main(), mesmo sem ter realizado o load da classe Lava. A maioria das implementações irá realizar esse mesmo processo para todas os tipos, ou seja, não irá realizar o loading de todos os tipos que serão utilizados pela aplicação, mas somente conforme a demanda pelo tipo for ocorrendo é que estes serão carregados dentro da Method Area.
Dentro das entranhas do método main(String[])
A primeira linha de código dentro do método main(), indica que a JVM deverá alocar memória suficiente para alocar a classe Lava. Para tanto, a JVM utiliza o ponteiro para a classe Vulcao que está setado na Constant Pool e acha uma referencia simbólica para a classe Lava. Nesse momento, a Method Area é acionada para verificar se as informações da classe Lava já foram carregadas.
A referencia simbólica é apenas uma String que dá o fully qualified name da classe Lava, ou seja, para essa classe o retorno seria a String: “br.com.mauda.arquitetura.methodArea.Lava“. Dessa forma é valido observar que a estrutura da Method Area deve ter a capacidade de localizar a classe Lava apenas pelo seu fully qualified name, podendo dessa forma utilizar Hash Tables, Arvores de Busca Binária, entre outros tipos de estrutura de dados para atender essa demanda.
Nesse nosso exemplo, a JVM irá descobrir que a classe Lava ainda não foi carregada para a Method Area. Dessa forma, através de um Class Loader novamente, ela irá carregar os bytes codes encontrados no arquivo Lava.class, extraindo a definição dessa classe para serem armazenados na Method Area.
Após o carregamento, a JVM irá substituir a referencia simbólica, no Constant Pool da classe Vulcao, apenas pela String “Lava“, a qual aponta para as informações carregadas na Method Area. Se a JVM necessitar utilizar a referencia a classe Lava via Constant Pool da classe Vulcao, o processo será mais rápido, pois a classe Lava já estará carregada na Method Area, acessando diretamente o ponteiro para esta área. Assim esse processo, chamado de Constant Pool Resolution, substitui a referencia simbólica por uma referencia direta à classe na Method Area.
Alocando Memória…
Finalmente, a JVM está pronta para alocar a memória para a nova instancia da classe Lava. Mais uma vez, a JVM consulta as informações sobre a classe armazenada na Method Area, através do ponteiro dentro da classe Vulcao da Constant Pool. Esse processo de consulta irá retornar o tamanho do espaço necessário para alocar esse novo objeto da classe Lava na Heap (A ser apresentada em um novo artigo em breve).
A JVM pode sempre determinar o espaço necessário para realizar uma alocação de memória de uma nova instância de um tipo, observando as informações presentes sobre este dentro da Method Area. Mas o verdadeiro espaço ocupado por essa instância depende da implementação da JVM.
Assim que a JVM determina o espaço necessário para inserir uma nova instância da classe Lava, ela aloca esse espaço dentro da Heap e inicializa o atributo velocidadeKmPorHora para Zero. Isso mesmo Zero! Mas por que isso? Porque esse é o valor default inicial para variáveis do tipo primitivo int. Se o pai da classe Lava, Object, tiver qualquer atributo interno, ele será inicializado com o valor default.
Após a alocação do espaço na Heap, os atributos serão inicializados, caso estes contenham algum valor a ser inserido. Isso ocorre a partir do topo da hierarquia de classes, assim se caso existam valores a serem inseridos em algum atributo da classe Object, estes o serão feitos nesse momento. Após isso irá descer na hierarquia para a próxima classe, realizando o mesmo processo de inicialização. No nosso caso o atributo velocidadeKmPorHora irá receber o valor de Cinco.
O próximo passo é chamar o método construtor para realizar outros processos. Por fim o “retorno” do método construtor será uma nova instância do tipo requisitado. A próxima parte da primeira linha de código do método main(String[]) será atribuir a nova instância de Lava a uma referencia, de nome lava. Essa referencia será armazenada dentro da Stack.
finnaly{
Em um próximo artigo estarei apresentando a subárea Heap não perca!
Duvidas ou sugestões? Deixe seu feedback! Isso ajuda a saber a sua opinião sobre os artigos e melhorá-los para o futuro! Isso é muito importante!
Até um próximo post!
Leave a Reply