JVM运行时数据区与JVM指令集

JVM运行时数据区与JVM指令集_第1张图片

一、程序计数器(ProgramCounter)

  • 具有线程隔离性
  • 占用的内存空间非常小,可以忽略不计
  • java虚拟机规范中唯一一个没有规定任何OutofMemeryError的区域
  • 程序执行的时候,程序计数器是有值的,其记录的是程序正在执行的字节码的地址

二、虚拟机栈( Java Stack )

虚拟机栈

一个线程对应一个栈,一个栈对应多个方法栈帧, 栈帧包含局部变量表、操作数栈、动态连接、方法出口等

int i = 8;
i = i++;
 0 bipush 8	压栈
 2 istore_1	赋值出栈
 3 iload_1	压栈
 4 iinc 1 by 1	+1
 7 istore_1	赋值出栈
 8 getstatic #3 
11 iload_1	
12 invokevirtual #4 
15 return
  1. 基于寄存器的指令集

  2. 基于栈的指令集

    1. HotSpot中的Local Variable table = JVM中的寄存器
  3. JVM指令主要分为:本地变量表到操作数栈类指令、操作数栈到本地变量表类指令、常数到操作数栈类指令、将数组指定索引的数组推送至操作数栈类指令、将操作数栈数存储到数组指定索引类指令、操作数栈其他相关类指令、运算相关类指令、条件转移类指令、类和数组类指令和其他指令。

  4. i开头的指令操作数类型是integer类型,l开头的指令操作数类型是long类型,f开头的指令操作数类型是float类型,d开头的指令操作数类型是double,a开头的指令操作数类型是引用类型(reference)。

  5. load类指令将数据从本地变量表加载到操作数栈,store类指令将数据从操作数栈存储到本地变量表中。其他的指令主要用于操作数栈。

三、本地方法栈( Native Method Stack )

  • Java虚拟机栈于管理Java方法的调用,而本地方法栈用于管理本地方法的调用
  • 本地方法栈,也是线程私有的。
  • 允许被实现成固定或者是可动态扩展的内存大小
    • 如果线程请求分配的栈容量超过本地方法栈允许的最大容量,Java虚拟机将会抛出一个stackoverflowError 异常。
    • 如果本地方法栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的本地方法栈,那么Java虚拟机将会抛出一个outofMemoryError异常。
  • 本地方法一般是使用C语言实现的。
  • 它的具体做法是Native Method Stack中登记native方法,在Execution Engine 执行时加载本地方法库。

注意点:

当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。它和虚拟机拥有同样的权限。

  • 本地方法可以通过本地方法接口来访问虚拟机内部的运行时数据区
  • 它甚至可以直接使用本地处理器中的寄存器
  • 直接从本地内存的堆中分配任意数量的内存

并不是所有的JVM都支持本地方法。因为Java虚拟机规范并没有明确要求本地方法栈的使用语言、具体实现方式、数据结构等。如果JVM产品不打算支持native方法,也可以无需实现本地方法栈。

在Hotspot JVM中,直接将本地方法栈和虚拟机栈合二为一

四、堆内存(Direct Memory)

JVM运行时数据区与JVM指令集_第2张图片

  • 年轻代:新对象和没达到一定年龄的对象都在年轻代。
  • 老年代:被长时间使用的对象,内存空间应该要比年轻代更大。
  • 元空间:元空间不在虚拟机设置的内存中,而是使用本地内存。是对方法区的一种实现
    • 最初的永久代是需要在JVM堆内存里面进行划分。

五、方法区(Method Area)

  • 存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等

  • 方法区的垃圾收集主要回收两部分内容:常量池中废弃的常量和不再使用的类型。

    • 该类所有的实例都已经被回收,也就是Java堆中不存在该类及其任何派生子类的实例。
    • 加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加载器的场景,如OSGi、 JSP的重加载等,否则通常是很难达成的。
    • 该类对应的java. lang. Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
  • 方法区在JVM启动的时候被创建,并且它实际的物理内存空间中和Java堆区一样都可以是不连续的。

  • 方法区的小大,跟堆空间一样,可以选择固定大小或者可扩展

  • 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误:java.lang.OutOfMenoryError:Metaspace

  • 关闭JVM就会释放这个区域的内存

变化

JDK1.6及其以前:有永久代,静态变量存放在永久代上。

JDK1.7:有永久代,但已经逐步“去永久代”,字符串常量池、静态变量移除,保存在堆中。

JDK1.8及其之后:无永久代,类型信息、字段、方法、常量保存在本地内存的元空间,但字符串常量池、静态变量仍在堆。

你可能感兴趣的:(jvm)