2015-05-07 27 views
4

因此,这里的例子:什么做“开始”和LocalVariableTable“长度”属性意味着

LocalVariableTable: 
     Start Length Slot Name Signature 
       0  133  0 this Lcom/my/class/Test; 
       2  131  1  a I 
       4  129  2  b I 
       7  126  3  i I 
       10  123  4 i2 I 
       16  117  5 o1 Ljava/lang/Integer; 
       31  102  6 o2 Ljava/lang/Integer; 

什么是启动和长度是什么意思?为什么长度有它的价值?为什么相同类型(整数)的长度不同?为什么长度可以改变,当我添加一些东西给类并重新编译它而不触及特定的局部变量?

回答

7

开始是该变量可见的起始字节码偏移量。长度是此变量可见的字节码字节数。通常起始点指向首先分配变量的字节码指令,或者指向方法参数0和this。在你的情况下,似乎所有的变量在方法的末尾都是有效的(每个变量为start+length = 133),但是如果你在块内声明了一些变量,它们的作用域会缩短。

请注意,局部变量表(LVT)是一个可选的调试信息。程序不需要执行,编译期间可以使用-g:none关闭。该表的主要目的是为了使调试更加方便:让您可以为每个字节码确定哪些变量当前可见,以便在变量窗格中显示它们并在离开变量范围后隐藏它们。此表也被Java反编译器和代码分析器如FindBugs使用。

+0

非常感谢您的回答。如果你不介意,我想根据你的回答提出另一个问题。如果你说LVT是可选的,它的目的只是用于调试,那么如何将以局部变量索引作为参数(例如,aload)的java操作码正在工作呢?当没有LVT时,局部变量信息是否存储在其他地方? – dhblah

+1

“this”(对于非静态方法)和方法参数(每个“long”/“double”2个槽,其他类型为1个槽)将自动使用第一个槽,这可以通过方法签名来决定。在那之后,如果JVM看到一个用于新插槽的存储指令,它就简单地分配这个插槽(或者'lstore' /'dstore'的两个插槽),并根据操作码设置其类型。在已验证的字节码中,不应该有从未知时隙加载的加载指令(不是由方法参数或先前的存储指令占用)。 –

+0

所以基本上你会说,虽然LVT可以在编译时被丢弃,但它仅用于信息目的。并且所有与JVM所需的局部变量相关的数据都存储在堆栈帧中的局部变量数组中。因此,本地变量可以通过它们在该数组中的索引来寻址,而LVT仅包含补充信息,以便在调试期间在调试窗格的正确步骤中显示\隐藏本地变量。 – dhblah

1

根据jsl

内部本地variabale表

u2 local_variable_table_length; 
    { u2 start_pc; 
     u2 length; 
     u2 name_index; 
     u2 descriptor_index; 
     u2 index; 
    } 

的local_variable_table阵列中的每个条目指示的范围内码阵列 偏移在其内的局部变量具有一个值的。它还将指数 指示到可以找到该局部变量的当前帧的局部变量数组中。

现在为起点和长度属性JSL说

start_pc,长度

阵列在区间[start_pc,start_pc +长度),即, start_pc包容和start_pc之间+长度独家。

The value of start_pc must be a valid index into the code array of this 

代码属性并且必须是指令的操作码的索引。

The value of start_pc + length must either be a valid index into 

这个代码属性的代码阵列和是一个指令的操作码 的索引,或者它必须超出码阵列的端部的第一索引。

所以基本上开始对应于你LineNumberTable