JvmmemoryModel
Este artigo apresenta principalmente a área de dados de tempo de execução (Runtimedataareas) descrita na especificação da JVM. Essas áreas são projetadas para armazenar dados usados pela própria JVM ou programas em execução na JVM.
Vamos primeiro visão geral da JVM, depois apresentar o bytecode e, finalmente, introduzir diferentes áreas de dados.
Visão geral
Como abstração do sistema operacional, a JVM garante que o mesmo código se comporte de forma consistente em diferentes hardware ou sistemas operacionais.
por exemplo:
Para o tipo básico INT, é um número inteiro assinado de 32 bits, independentemente do sistema operacional de 16 bits/32 bits/64 bits. Varia de -2^31 a 2^31-1
Independentemente de o sistema operacional ou hardware ser uma ordem de bytes grande ou pequena, é garantido que os dados na memória armazenados e usados pela JVM sejam grandes ou pequenos de bytes (leia o byte de alto bit)
Diferentes implementações de JVM podem diferir um pouco, mas geralmente são as mesmas.
A imagem acima é uma visão geral de uma JVM
A JVM interpreta o bytecode gerado pelo compilador. Embora a JVM seja a abreviação de máquinas virtuais Java, desde que seja uma linguagem que possa ser compilada no bytecode, ela pode ser executada com base na JVM, como Scala, Groovy <� "/kf/ware/vc/" Target = "_ Blank"> VCD4NCJXWPS6QWCUX3MPIXRW3SBXETMXFZEKVT6OS19A92SLRU+GXU2NSYXNZBG9HZGVYVNPU2LKIU7Q05R W91mvq0mqxyv2+3cf41tc1xnk7upbh+npyo6zwqrxavnpu2mv8tcrjbgfzc2xvywrlcrg7z/q72bvy1d9kvk3no9a51mvq0kgjpc 9wpg0kpha+vnpu2lxe19a92slrzai5/da00nds/cfmkgv4zwn1dglvbiblbmdpbmupvfjq0l3iys26zda00na8l3a+dqo8cd7wt Ndq0v3h5tdo0qq05rsis8zq8snpz8loxkossCJi57pm0plwtndqtb3exnk70ncjrlvy1d/k/b7dvmbl47xE1tc85l3HUFS8l3A+d Qo8cd7wtndq0v3h5tkyulru8lsmwo3t67xxsuoy2df3z7xns7xevbu7ptwvcd4ncjxwpioquty24epwtba8yrxp1shlvltksbhg 0UU5PSTCKEPJVD1QDXN0IGLUIHRPBWUPOANKSVS+ZCRHSNG+RBOJ1RTQ0LXETPRC6YJIYLXJTPRC6YMX4NLRS8MXVRXYTPRC6YHO Yxrpdmugq29kzsmho7tmt8vksvsx4nlryfqzybt6wuu1xmf40/kzxs6qpc9wpg0kpha+tprc67u6tobh+chdb2rlienh Y2GPOAO8TMQXSEDS67Y8YVUOSKLUKBY2TPO1XMZHUN/BY0PWTBXE0NTE3COQPC9WPG0KPGGYIGLKPQ == "Baseado em pilha Arquitetura "> Arquitetura baseada em pilha
A JVM usa uma arquitetura baseada em pilha. Embora a pilha seja transparente para os desenvolvedores, ela tem um papel ou influência muito importante no bytecode e JVM gerado.
Os programas que desenvolvemos converterão operações de baixo nível e as armazenam em bytecode. Mapa para instruções de operação através de operando na JVM. De acordo com a especificação da JVM, os parâmetros exigidos pelas instruções de operação são obtidos na pilha de operando.
Vamos dar um exemplo de adição de dois números. Esta operação é chamada IADD. A seguir, o processo de 3+4 no bytecode
Primeiro push 3 e 4 na pilha de operando
Ligue para a Diretiva IADD
A instrução IADD aparece 2 números do topo da pilha de operando
O resultado de 3+4 é empurrado para a pilha de operando para uso posterior
Essa abordagem é chamada de arquitetura baseada em pilha. Existem outras maneiras de lidar com operações de baixo nível, como a arquitetura baseada em registro.
Bytecode
Java Bytecode é o resultado da conversão do código-fonte Java em uma série de operações de baixo nível. Cada operação consiste em um código de operação ou código de operação com parâmetros de comprimento zero ou mais bytes (mas a maioria das operações usa parâmetros obtidos através da pilha de operando). Um byte pode representar 256 números, de 0x00 a 0xFF, e atualmente para Java8, um total de 204 são usados.
Os seguintes listos diferentes tipos de opcode de bytecode, bem como seu alcance e descrição simples
Constantes: empurre o valor do pool constante ou um valor conhecido na pilha de operando. 0x00 - 0x14
Cargas: empurre os valores da variável local na pilha de operando. 0x15 - 0x35
Lojas: Valor de carregamento da pilha de operando para variável local 0x36 - 0x56
Pilha: operando de processo pilha 0x57 - 0x5f
Matemática: Obtenha valor da pilha de operando para cálculo matemático básico 0x60 - 0x84
Conversões: converta entre os tipos 0x85 - 0x 93
Comprisons: operação de comparação de dois valores 0x94 - 0XA6
Controles: execute goto, retorno, loop, etc. Operações de controle 0XA7 - 0xb1
Referências: executa objetos ou matrizes de alocação e obtém ou verifica referências a objetos, métodos e métodos estáticos. Métodos estáticos também podem ser chamados. 0xb2 - OXC3
Estendido: estendido: operações das outras categorias que foram adicionadas depois. Do valor 0xc4 a 0xc9
(O que essa frase significa?
Reservado: a implementação da JVM usa slots 0xca, oxfe, oxff
Essas 204 operações são muito simples, dão alguns exemplos
ifeq (0x99) determina se os dois valores são iguais
IADD (0x60) adiciona dois números
I2L (0x85) converte um pouco de muito tempo
ArrayLength (0XBE) retorna o comprimento da matriz
POP (0x57) coloque um valor da parte superior da pilha de operando
Precisamos de um compilador para criar arquivos de bytecode, e o compilador Java padrão é JAVAC no JDK.
classe pública teste {public static void main (string [] args) {int a = 1; int b = 15; int resultado = add (a, b); } public static int add (int a, int b) {int resultado = a + b; resultado de retorno; }}Você pode obter o arquivo bytecode de "test.class" através de "javac test.java". Os arquivos de bytecode são binários, podemos converter arquivos binários binários em formulário de texto através de javap
java -verbose test.class
ClassFile /c:/tmp/test.class Último modificado 1 AVR. 2015; tamanho 367 bytes md5 soma de verificação adb9ff75f12fc6ce1cdde22a9c4c7426 Compilado em "test.java" classe pública com.codinggeek.jvm.test Sourcefile: "test.java" Menor versão: 0 maior versão: 51 FAGNS: ACC__PUBLIC. java/lang/objeto. LineNumberTable #9 = utf8 main #10 = utf8 ([ljava/lang/string;) v #11 = utf8 adicione #12 = utf8 (ii) i #13 = utf8 fonte #14 = utf8 test.java #15 = namAndTe #Eann: #6 // "<init>" #17 = utf8 com/codinggeek/jvm/teste #18 = utf8 java/lang/objeto {public com.codinggeek.jvm.test (); Sinalizadores: Acc_public Código: Stack = 1, habitantes locais = 1, args_size = 1 0: aload_0 1: InvokesPpecial #1 // Método java/lang/objeto. "<ingem>" :() v 4: retornar lineNumberTable: linha 3: 0 public static void main (java.Lang.string []; Sinalizadores: Acc_public, Acc_static Code: Stack = 2, habitantes locais = 4, args_size = 1 0: iconst_1 1: istore_1 2: bipush 15 4: istore_2 5: iload_1 6: iload_2 7: Invokestatic #2 // Método: (ii) i 10ee. 8: 5 Linha 9: 11 public static int add (int, int); Sinalizadores: Acc_public, Acc_static Code: Stack = 2, habitantes locais = 3, args_size = 2 0: iload_0 1: iload_1 2: iAdd 3: istore_2 4: iload_2 5: linenumbertable: linha 12: 0 linha 13: 4}Pode -se observar que o bytecode não é apenas uma tradução simples do código Java, inclui:
Uma descrição constante da piscina da classe. Os pools constantes são áreas de dados JVM usadas para armazenar metadados da classe, como nomes de métodos, listas de parâmetros etc. dentro da classe. Quando a JVM carrega uma classe, os metadados serão carregados na piscina constante
Forneça as informações de posição específicas das funções e das variáveis tmall no bytecode através da tabela de números da linha e da tabela de variáveis locais.
Tradução do código Java (incluindo construções ocultas da classe pai)
Fornece operações mais específicas sobre pilhas de operando e maneiras mais completas de passar e obter parâmetros
Abaixo está uma descrição simples das informações de armazenamento de arquivo de bytecode
ClassFile {U4 Magic; U2 Minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool [constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; U2 interfaces [interfaces_count]; U2 campos_count; campos field_info [campos_count]; U2 atributes_count; atributo_info atributos [attributes_count];}Área de dados de tempo de execução
A área de dados de tempo de execução é a área de memória projetada para armazenar dados. Esses dados são para uso por desenvolvedores ou JVM internamente.
Pilha
A pilha é criada quando a JVM é iniciada e é compartilhada por todos os threads JVM. Todas as instâncias e matrizes de classe são alocados para o heap (criado por novo).
O heap deve ser gerenciado por um coletor de lixo, responsável por liberar objetos criados pelo desenvolvedor e não será usado novamente.
Quanto à estratégia de coleta de lixo, ela é determinada pela implementação da JVM (por exemplo, o ponto de acesso fornece vários algoritmos).
Há um limite máximo para a memória da pilha. Se esse valor for excedido, a JVM lançará uma exceção ou exceção.
Área de método
A área do método também é compartilhada por todos os threads da JVM. O mesmo é criado com a JVM Startup. Os dados armazenados na área do método são carregados do bytecode pelo carregador de classe, que existirá de forma consistente durante a execução do aplicativo, a menos que o carregador de classe os carregue seja destruído ou a JVM.
A área do método armazena os seguintes dados:
Informações da classe (nome do atributo, nome do método, nome da classe pai, nome da desculpa, versão, etc.)
Métodos e bytecodes construídos
Pool constante de tempo de execução criado ao carregar cada classe
A especificação da JVM não força as áreas de método a serem implementadas na pilha. Antes do Java7, o HotSpot implementou as zonas de método usando uma região chamada Permgen. A banda permanente é adjacente à pilha (o gerenciamento da memória é o mesmo que o heap), o bit padrão é de 64 MB
A partir do Java8, o HPTSpot usa uma memória local separada para implementar a área do método e nomear a área de metadados (Metaspace). O espaço máximo disponível na área de metadados é a memória disponível de todo o sistema.
Se o método não puder se inscrever na memória disponível, a JVM também lançará o ExterfMemoryError.
Pool constante de tempo de execução
O pool constante de tempo de execução faz parte da área do método. Devido à importância de executar um pool constante em metadados, ele é descrito separadamente na especificação Java fora da área do método. O pool constante de tempo de execução cresce com as classes e interfaces carregadas.
Pools constantes são uma tabela de sintaxe nos idiomas tradicionais. Em outras palavras, quando uma classe, método ou propriedade é chamada, a JVM procura o endereço real desses dados na memória através do pool constante de tempo de execução. Pool constante de tempo de execução também contém constantes de literais de cordas ou tipos primitivos
Stirng myString = "Este é um string lateral" estático final int my_constant = 2;
PC (registro do contador de programas) (por thread) o registro do PC (por thread)
Cada thread possui seu próprio registro de PC (contador de programas), criado juntamente com a criação de threads. Cada encadeamento pode executar apenas um método em um momento, chamado de método atual do thread. O registro do PC contém o endereço da JVM atualmente executando a instrução (na área do método).
Se o método atualmente executado for um método local, o valor do registro do PC será indefinido
Pilha de máquina virtual por thread-java-virtual-machine Stacks-per-thread "> pilha de máquinas virtuais (por thread) pilhas de máquina virtual java (por thread)
A pilha de máquinas virtuais armazena vários quadros; portanto, antes de descrever a pilha, vamos dar uma olhada primeiro nos quadros.
Quadros
Um quadro é uma estrutura de dados que contém vários dados que representam o método atual afirmam que o encadeamento está executando:
Pilha de operando: como mencionado anterior, as instruções do bytecode usam pilha de operando para passar os parâmetros
Matriz de variáveis local: esta matriz contém todas as variáveis locais dentro de um escopo do método atualmente executado. Esta matriz pode conter um tipo primitivo, uma referência ou um endereço de retorno. O tamanho da matriz variável local é determinado no momento da compilação. A JVM usa variáveis locais para passar os parâmetros ao chamar o método, e a matriz variável local do método chamada é criada através da pilha de operando do método de chamada.
REFERÊNCIA CONSTANTE DE RUNDO Time de tempo: Referências ao pool constante do método atual da classe atual. A JVM usa referências constantes de pool para passar sinais para referências reais de memória.
Pilha (pilha)
Cada thread JVM possui uma pilha JVM privada, criada ao mesmo tempo que o thread. Java Virtual Machine Stack armazena quadros. Cada vez que um método é chamado, um quadro é criado e empurrado para a pilha de máquina virtual. Quando esse método é executado, o quadro também será destruído (independentemente de o método ser executado normalmente ou uma exceção é lançada)
Apenas um quadro está disponível durante a execução de um thread. Esse quadro é chamado de quadro atual.
As operações em variáveis locais e pilhas de operando geralmente são acompanhadas por referências ao quadro atual.
Vejamos outro exemplo de adição
public int add (int a, int b) {return a + b;} public void functionA () {// Algum código sem a função chamada de resultados = add (2,3); // Ligue para funcionar para funcionar b // algum código sem chamada de função}Método interno A, o quadro A é o quadro atual, localizado na parte superior da pilha da máquina virtual. No início de chamar o método Add, um novo quadro B é criado e empurrado para a pilha de máquina virtual. O quadro B se torna o novo quadro atual.
A matriz variável local do quadro B é preenchida com dados na pilha de operando do quadro A. Quando o método Add termina, o quadro B é destruído e o quadro A é restabelecido como o quadro atual. O resultado do método ADD é empurrado para a pilha de operando do quadro A, para que o método a possa obter o resultado de add através da pilha de operando do quadro A.
Resumir
O exposto acima é sobre a análise da área de dados do tempo de execução da máquina virtual Java. Espero que seja útil para todos.
Se houver alguma falha, deixe uma mensagem para apontá -la.