JVM体系结构
jvm内部体系结构分三部分:类加载器 执行引擎 运行时数据区
类加载器 加载.class文件。
三个步骤:(1)装载。jvm通过ClassLoader 类名 包名将类的二进制字节码加载到jvm中完成类的加载工作。可以通过“类名+包名+ClassLoader实例ID”来标识一个被加载的类。
(2)链接。加载完后,对二进制字节码格式进行验证,初始化加载类的静态变量并赋值为默认值,最后对类中方法、属性进行验证,确保其需要调用的属性、方法存在及具备相应权限(验证public private等)。
(3)初始化。执行类中的静态初始化代码、构造器代码以及静态属性的初始化。以下四种情况初始化过程被触发:调用new 反射调用类中方法 子类调用初始化 jvm启动过程中指定的初始化类。
java对象模型成为“OOP-Klass‘‘。一个java对象包括两部分,OOP和Klass,OOP指java实例对象,Klass指java类的信息。
jvm运行加载一个Class时,会在jvm内部创建一个instanceKlass对象,存在于方法区,表示这个类的运行时元数据(即类的基本信息)。创建这个Class的java对象时,会在堆内创建一个instanceOop来表示这个java 对象,对象的引用放在jvm栈中。
执行引擎 执行字节码或者执行本地方法(native方法 系统底层方法)
JVM通过执行引擎来完成字节码的执行,JVM采用自己的一套指令系统。每个线程在创建后,都会产生一个程序计数器(pc)和栈(Stack),其中程序计数器中存放了下一条将要执行的指令,Stack中存放栈帧(Stack Frame)。JVM是基于栈来运行的,当一个线程调用一个对象的方法时,会在它的JVM栈的栈顶创建一个栈帧(Frame)的数据结构,这个数据结构是用来保存方法的局部变量,操作数栈,动态连接(java 对象的引用)和方法返回值的。通过参数传递的值和在方法中new出来的对象的引用都保持在局部变量表里面。操作数栈用于存放指令运算的中间结果,指令负责从操作数栈中弹出参与运算的操作数,指令执行完毕后再将计算结果压回到操作数栈,当方法执行完毕后则从Stack中弹出,继续其他方法的执行。
运行时数据区 方法区 堆 栈 PC寄存器 本地方法栈
PC寄存器 PC寄存器是用于存储每个线程下一步将执行的JVM指令,如该方法为native的,则PC寄存器中不存储任何信息
JVM栈 JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中(栈帧)存放的为当前线程中局部基本类型的变量,部分返回结果以及函数的参数值,操作数栈,非基本类型的对象的JVM栈上仅存放一个指向堆上的地址(即java 对象的引用)
堆(Heap) Heap是大家最为熟悉的区域,它是JVM用来存储对象实例以及数组值的区域,可以认为java中所有通过New创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。
方法区域(Method Area)(1)方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,可见方法区域的重要性,同样,方法区域也是全局共享的,在一定的条件下它也会被GC;当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。
(2)在Sun JDK中这块区域对应的为Permanet Generation,又称为持久代,默认为64M,可通过-XX:PermSize以及-XX:MaxPermSize来指定其大小
运行时常量池(Runtime Constant Pool)
类似C中的符号表,存放的为类中的固定的常量信息、方法和Field的引用信息等,其空间从方法区域中分配。
本地方法堆栈(Native Method Stacks)
JVM采用本地方法堆栈来支持native方法的执行,此区域用于存储每个native方法调用的状态
注:转自网络 只为学习。