jvm的基本结构
1.类加载系统 负责从文件系统或者网络中加载Class信息
2.方法区
(1)加载的类信息存放于一块称为方法去的内存空间
(2)除了类的信息外,方法区中可能还存放着运行时常量池信息,包括字符串字面量和数字常量(这部分常量信息是Class文件中常量池部分的内存映射)是所有线程共享的
3.java堆
java堆是在虚拟机启动的时候建立的,她是java程序中最主要的内存工作区域,几乎所有的java对象和数据都顿放在java堆中,堆空间是所有线程共享的。
4.直接内存
java的NIO库允许java程序使用直接内存,在Nio被广泛使用后,直接内存的使用也变得非常普通
直接内存是Java堆外的,直接向系统申请的内存空间,访问速度会大于Java堆,它的空间大小只会受操作系统给出的最大内存影响,与java堆相比,虽然在访问读写上,直接内存有较大的又是,但是在内存空间申请上,堆空间的数据远远高于直接内存。
结论:直接内存时候内存空间申请次数较少,访问较频繁的场合。
5.java栈
java栈是线程私有的,他在线程创建的时候被创建
java栈中保存着栈帧信息,局部变量,方法参数,同时和Java方法的调用,返回密切相关
6.本地方法栈
与java栈非常类似,最大的不同在于java栈用于Java方法的调用,而本地方法栈则用于native方法调用。
7.PC寄存器
她是线程私有的,如果正在执行的方法不是本地方法,PC寄存器就会指向当前正在被执行的指令
如果当前方法是本地方法,当么PC寄存器的值就是undefined
8.垃圾回收系统
GC可以对方法去,Java堆,直接内存进行回收
Java堆是GC的工作重点,java中所有对象空间释放都是隐式的。
9.执行引擎
是java虚拟机的最核心组件之一,负责执行虚拟机的字节码。
Class类加载
1.ClassLoader对类进行加载
主动加载的4种情况
(1)new一个对象实例的时候
(2)利用反射或者clone的时候
(3)初始化子类时候,父类会优先初始化
(4)调用一个类的静态方法时。
2.类的加载步骤
(1)加载ClassLoader
通过类的全路径名称,获取二进制数据流
解析类的二进制流转化为方法区(永久代or元空间)内部的数据结构。
创建java.long.Class类的实例对象,表示该类型
(2)验证
目的时保证第一步种加载的字节码文件时合法切符合规范的。
主要分为
格式检查:检查魔数,版本,长度,
语义检查:抽象方法是否有实现类,是否继承了final类等等编码语义上的错误检查
字节码验证:跳转指令是否指向正确的位置,操作数类型是否合理
符号引用验证:符号引用的直接引用是否存在
(3)准备
准备阶段时正式为类变量分配内存并设置类变量的初始值阶段,即在方法区中分配直接变量所使用的内存空间。
注意这里面所说的初始值概念,比如一个类变量定义为 public static int v = 8080;实际上变量v在准备阶段过后的初始值为0不是8080,将V赋值为8080的public static指令时程序编译后,存放于类构造器<client>方法中,但是注意如果声明为 public static final int v = 8080 在编译阶段会为V生成ConstantValue属性,在准备阶段虚拟机会根据ConstantValue属性将V赋值为8080
(4)解析
解析阶段是指虚拟机将运行时常量池中的符号引用替换为直接引用的过程,符号引用就是class文件中CONSTANT_Class_Info,CONSTANT_Field_info,CONSTANT_Method_info等类型的常量
(5) 初始化
到达这个阶段,类就可以顺利加载到系统中,此时类才会开始执行java字节码。
初始化阶段时执行类构造器<client>方法的过程,<Client>方法是由编译器自动收集类中的类类变量的赋值操作和静态语句块种的语句合并而成的,虚拟机回保证子<client>方法执行之前,父类的<client>方法已经执行完毕,如果一个类中没有对静态变量赋值也没有静态与巨款,那么编译器可以不为这个类生成<client>()方法。
3.符号引用和直接引用
在解析阶段会有一个步骤,将运行时常量池当中的二进制数据当中的符号引用转化为直接引用的过程
符号引用
以一组符号来描述所引用的飙
符号引用可以是任何形式的字面量,只要使用时能无歧义的定位到目标即可,符号引用和虚拟机引用的布局无关
为什么要有符号引用?
在编译的时候每个java类都会编译成一个class文件,但在编译的时候虚拟机并不知道所引用类的地址,所以就用符号引用来代替,而在解析阶段就是为了把这个符号引用转化为真正的地址的阶段。
直接引用
直接引用和虚拟机的布局是相关的,不同的虚拟机对于相同的符号引用所翻译出来的直接引用一般是不同的
如果有了直接引用,那么直接引用的目标一定被加载到了内存中。
直接引用可以是:
直接指向目标的指针-----指向对象,类变量和类方法的指针
相对偏移量----指向实例的变量,方法的指针
一个简介定位到对象的句柄