Os subcontextos em Java são linhas separadas na pilha?
Pergunta
Em Java é o caso:
public void method() {
if (condition) {
Object x = ....;
}
System.out.println(x); // Error: x unavailable
}
O que estou me perguntando é o seguinte:É o fato de que x
está limitado ao âmbito do if
-statement é apenas um recurso do compilador Java ou é x
realmente removido da pilha após o if
-declaração?
Solução
Não, os blocos de código não recebem um quadro de pilha separado, o uso do método circundante.
No entanto, uma vez que uma variável deixa o escopo, é o lugar no quadro da pilha atual pode ser reutilizado para outras variáveis.
A estrutura e o uso de um quadro de pilha são descritos no Especificação da máquina virtual Java § 3.6 quadros:
Um novo quadro é criado sempre que um método é chamado. Um quadro é destruído quando a sua invocação de método é concluída, seja essa conclusão normal ou abrupta (lança uma exceção não capturada).
Isso definitivamente especifica uma relação 1: 1 entre invocações e quadros de métodos.
Outras dicas
Os blocos fazem parte da linguagem Java (que é uma linguagem de programação estruturada) embora não façam parte do bytecode compilado (que é um não estruturado linguagem).
Uma especificação de método em um arquivo de classe especifica quantas variáveis locais o método usa no total, acima da lista real de instruções.Mas onde os blocos uma vez estão no código Java não podem ser inferidos a partir do bytecode.
Em primeiro lugar, no bytecode as variáveis são armazenadas nos slots de variáveis e nos slots de variáveis e não na pilha.O slot pode ser reutilizado por outra variável, mas não é garantido que o valor seja removido do slot da variável.
Por exemplo, a seguinte classe
public class A {
public void method(boolean condition) {
6 if (condition) {
7 Object x = "";
8 System.out.println(x);
9 }
10 System.out.println(condition);
}
}
é compilado neste bytecode:
// class version 50.0 (50)
public class A {
...
// access flags 0x1
public method(Z)V
L0
LINENUMBER 6 L0
ILOAD 1
IFEQ L1
L2
LINENUMBER 7 L2
LDC ""
ASTORE 2
L3
LINENUMBER 8 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 2
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L1
LINENUMBER 10 L1
FRAME SAME
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ILOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (Z)V
L4
LINENUMBER 11 L4
RETURN
L5
LOCALVARIABLE this LA; L0 L5 0
LOCALVARIABLE condition Z L0 L5 1
LOCALVARIABLE x Ljava/lang/Object; L3 L1 2
MAXSTACK = 2
MAXLOCALS = 3
}
Observe que a variável x criada na linha 7 é armazenada no slot de variável 2, que ainda está disponível no bytecode correspondente à linha 10.
Não há nenhuma especificação sobre como a linguagem Java deve ser compilada no bytecode, além de alguns exemplos de como compilar corretamente algumas construções de linguagem.No entanto, o compilador Java pode eliminar variáveis não utilizadas.Por exemplo.se x foi atribuído, mas não usado em nenhum lugar, o compilador poderá descartar esse código.Da mesma forma, o compilador está incorporando todas as constantes estáticas.
Sim, ele é realmente removido da pilha, tornando o slot anteriormente ocupado por 'x' reutilizável por outra variável local.