java虚拟机笔记-1
java虚拟机学习笔记
Java技术的核心就是Java虚拟机,因为所有的Java程序都在虚拟机上运行。Java程序的运行需要Java虚拟机、Java API和Java Class文件的配合。Java虚拟机实例负责运行一个Java程序。当启动一个Java程序时,一个虚拟机实例就诞生了。当程序结束,这个虚拟机实例也就消亡。
java虚拟机结构图如下:
1、Java运行时数据区域
当类加载器将class文件加载到jvm后,Java虚拟机在执行java程序的过程中会把它管理的内存划分为若干个不同的数据区,java虚拟机所管理的内存将会包含以下几个运行时数据区域:
- 程序计数器(Program Counter Register)
- java虚拟机栈(Java Virtual Macchine Stacks)
- 本地方法栈(Native Method Stack)
- java堆(Java Heap)
- 方法区(Method Area)
- 运行时常量池(Runtime Constant Pool)
1-1、程序计数器:
程序计数器是一块较小的内存,可以被认作时当前线程所执行的字节码的行号指示器。字节码解释器通过改变计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖计数器实现。每个线程都需要一个独立的计数器,所有程序计数器不是线程共享的。
当线程执行的是java方法时,计数器记录当前正在执行的虚拟机字节码指令的地址,如果执行的是本地方法,则计数器值为空(Undefined),此内存也是唯一一个在虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
1-2、java虚拟机栈:
该区域也是线程私有的,它的生命周期与线程相同。每个方法在执行时都会创建一个帧栈用于存储局部变量表、操作数栈、动态链接、方法出口信息等,该区域规定了两种异常状况:StackOverflowError和OutOfMemoryError
每个方法从调用到执行完成的过程都会有一个人对应的帧栈在虚拟机栈中入栈出栈。栈由许多栈帧组成,一个栈帧包含一个Java方法调用的状态。当线程调用一个Java方法时,虚拟机压入一个新的栈帧到该线程的栈中,当该方法返回时,这个栈帧就从栈中弹出。Java栈存储线程中Java方法调用的状态–包括局部变量、参数、返回值以及运算的中间结果等。Java虚拟机没有寄存器,其指令集使用Java栈来存储中间数据。这样设计的原因是为了保持Java虚拟机的指令集尽量紧凑,同时也便于Java虚拟机在只有很少通用寄存器的平台上实现。另外,基于栈的体系结构,也有助于运行时某些虚拟机实现的动态编译器和即时编译器的代码优化。
1-2-1、局部变量区
局部变量区被组织为以字长为单位、从0开始计数的数组。字节码指令通过从0开始的索引使用其中的数据。类型为int, float, reference和returnAddress的值在数组中占据一项,而类型为byte, short和char的值在存入数组前都被转换为int值,也占据一项。但类型为long和double的值在数组中却占据连续的两项。
1-2-2、操作数栈
和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组。它通过标准的栈操作访问–压栈和出栈。由于程序计数器无法被程序指令直接访问,Java虚拟机的指令是从操作数栈中取得操作数,所以它的运行方式是基于栈而不是基于寄存器。虚拟机把操作数栈作为它的工作区,因为大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。
1-2-3、帧数据区
除了局部变量区和操作数栈,栈帧还需要帧数据区来支持常量池解析、正常方法返回以及异常派发机制。每当虚拟机要执行某个需要用到常量池数据的指令时,它会通过帧数据区中指向常量池的指针来访问它。除了常量池的解析外,帧数据区还要帮助虚拟机处理Java方法的正常结束或异常中止。如果通过return正常结束,虚拟机必须恢复发起调用的方法的栈帧,包括设置程序计数器指向发起调用方法的下一个指令;如果方法有返回值,虚拟机需要将它压入到发起调用的方法的操作数栈。为了处理Java方法执行期间的异常退出情况,帧数据区还保存一个对此方法异常表的引用。
未完待续。。。
相关文章