【JVM】1、Java内存区域

  • 程序计数器(Program Counter Register)
  • Java虚拟机栈(Java Virtual Machine Stacks)
    • 栈帧(Stack Frame)
      • 局部变量表
      • 操作数栈
      • 栈帧信息
  • 本地方法栈(Native Method Stack)
  • Java堆(Java Heap)
  • 方法区(Method Area)
    • 类信息
    • 常量
    • 运行时常量池(Runtime Constant Pool)
  • 直接内存(Direct Memory)

程序计数器(Program Counter Register)

当前线程所执行的行号指示器,记录「分支循环跳转异常处理线程回复等」。保证CPU在多个线程中切换执行代码能够找到正确的位置。
如果执行一个Java方法,记录正在执行的虚拟机字节码指令地址;如果执行Native方法,值为空。此区域是内存区域中唯一没有定义OutOfMemoryError情况的区域


Java虚拟机栈(Java Virtual Machine Stacks)

栈帧(Stack Frame)

每个Java方法在执行的时候都会创建一个栈帧(Stack Frame)用于储存「局部变量表操作数栈动态链接方法出口」等信息。每一个方法从调用到执行完成的过程,就对应一个栈帧在虚拟机栈中入栈到出栈的过程。

局部变量表

存放了编译期可知的原生数据类型和对象的引用(可能是对象在堆中的地址,也可能是一个对象的句柄地址或其他与该对象相关的位置)
局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈中分配多大的局部变量空间是完全可以确定的,在方法运行期间不会改变局部变量表的大小。

操作数栈

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

栈帧信息

1.动态链接,每个栈帧都包含一个指向运行时常量池中该栈帧所属性方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。在Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就常量池中指向方法的符号引用为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化,称为静态解析。另外一部分将在每一次的运行期期间转化为直接引用,这部分称为动态连接。
2.方法出口,方法正常退出时,调用者PC计数器的值就可以作为返回地址,栈帧中很可能会保存这个计数器值。而方法异常退出时,返回地址是 要通过异常处理器来确定的,栈帧中一般不会保存这部分信息。
3.附加信息,虚拟机规范允许具体的虚拟机实现增加一些规范里没有描述的信息到栈帧中,例如与高度相关的信息,这部分信息完全取决于具体的虚拟机实现。在实际开发中,一般会把动态连接,方法出口与其它附加信息全部归为一类,称为栈帧信息。


本地方法栈(Native Method Stack)

和虚拟机栈所发挥的作用相当,虚拟机栈为Java方法(字节码)服务,本地方法栈则为Native方法服务。


Java堆(Java Heap)

此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
但是随着JIT编译器的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象实例都在堆上分配内存渐渐变得不那么「绝对」了


方法区(Method Area)

用于储存被虚拟机加载的「类信息、常量、静态变量、及时编译器编译后的代码」等数据。
1.7的HotSpot虚拟机中,已经把原本放在永久代的字符串常量池移到堆中。

类信息

  1. 这个类型的完整有效名
  2. 这个类型直接父类的完整有效名(除非这个类型是interface或是java.lang.Object,两种情况下都没有父类)
  3. 这个类型的修饰符(public,abstract, final的某个子集)
  4. 这个类型直接接口的一个有序列表

除了以上的基本信息外,jvm还要为每个类型保存以下信息:类型的常量池( constant pool)、域(Field)信息、方法(Method)信息、除了常量外的所有静态(static)变量

常量

常量池就是这个类型用到的常量的一个有序集合,包括实际的常量(string, integer, 和floating point常量)和对类型,域和方法的符号引用。池中的数据项象数组项一样,是通过索引访问的。
因为常量池存储了一个类型所使用到的所有类型,域和方法的符号引用,所以它在java程序的动态链接中起了核心的作用。

运行时常量池(Runtime Constant Pool)

运行时常量池属于方法区的一部分,Java语言没有要求常量一定只有编译器才会能产生,运行期间也有可能将新的常量放入池中。


直接内存(Direct Memory)

并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域。但是这部分内存被频繁使用,而且也可能导致OutOfMemoryError。尤其是NIO中调用了Native方法直接分配堆外内存。

你可能感兴趣的:(【JVM】1、Java内存区域)