【JVM】1.1、局部变量表与操作数栈

  • 局部变量表
    • Slot重用与GC
  • 操作数栈
  • 局部变量表与操作数栈加法案例

局部变量表

  1. 大小固定,局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在Java程序被编译成Class文件时,就在方法的Code属性的max_locals数据项中确定了该方法所需要分配的最大局部变量表的容量。
  2. Slot单位,局部变量表的容量以变量槽(Slot)为最小单位,32位虚拟机中一个Slot可以存放一个32位以内的数据类型(boolean、byte、char、short、int、float、reference和returnAddress八种)所以那些比较小的类型也占用32位内存(如boolean、byte、char、short),而double和long为64位数据类型,他们需要两个连续的Slot存储(64位虚拟机中可能只需要一个),但如何保证其并发操作?
  3. 引用类型,reference类型(引用类型)虚拟机规范没有明确说明它的长度,但一般来说,虚拟机实现至少都应当能从此引用中直接或者间接地查找到对象在Java堆中的起始地址索引和方法区中的对象类型数据。
  4. Slot是可以重用的,当Slot中的变量超出了作用域,那么下一次分配Slot的时候,将会覆盖原来的数据。Slot对对象的引用会影响GC(要是被引用,将不会被回收)。
  5. 方法返回地址,returnAddress类型是为字节码指令jsr、jsr_w和ret服务的,它指向了一条字节码指令的地址。

Slot重用与GC

public static void main(String[] args) {
    {
        byte[] placeholder = new byte[1024 * 1024 * 64];
    }
    System.gc();
}

[GC (System.gc())  70779K->66200K(251392K), 0.0008518 secs]
[Full GC (System.gc())  66200K->66059K(251392K), 0.0055584 secs]

byte数组结束之后执行gc,因为Slot还被byte数组引用,结果在内存中未被回收。

public static void main(String[] args) {
    {
        byte[] placeholder = new byte[1024 * 1024 * 64];
    }
    int i = 0;
    System.gc();
}
[GC (System.gc())  70779K->66296K(251392K), 0.0009577 secs]
[Full GC (System.gc())  66296K->523K(251392K), 0.0051850 secs]

在gc上增加int复制操作,因为Slot的被int值复用,这次成功回收了byte数组。在gc上赋值byte数组为null也可以达到这样的效果,并且看起比int赋值来的更规范。 在实际编码中,因为java的特性,不做特殊处理,方法结束后局部变量表也会释放。


操作数栈

  1. 存储运算方式,和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组。但是和前者不同的是,它不是通过索引来访问,而是通过标准的栈操作—压栈和出栈—来访问的。比如,如果某个指令把一个值压入到操作数栈中,稍后另一个指令就可以弹出这个值来使用。
  2. 数据类型存储,虚拟机在操作数栈中存储数据的方式和在局部变量区中是一样的:如int、long、float、double、reference和returnType的存储。对于byte、short以及char类型的值在压入到操作数栈之前,也会被转换为int。
  3. 运算方式,虚拟机把操作数栈作为它的工作区——大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。

局部变量表与操作数栈加法案例

局部变量表与操作数栈加法案例
before starting // 加载100和98到局部变量表中
after iload_0   // 加载100到操作数栈中
after iload_1   // 加载98到操作数栈中
after iadd      // 操作100+98命令
after istore_2  // 弹出结果到局部变量表中

你可能感兴趣的:(【JVM】1.1、局部变量表与操作数栈)