类加载机制
虚拟机把class文件加载到内存,并对数据进行校验,转换解析和初始化,形成虚拟机可以直接使用的Java类型,即java.lang.class
装载(Load)
ClassFile -> 字节流 ->类加载器
查找和导入class文件
1:通过一个类的全限定名获取定义此类的二进制字节流
2:将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3:在Java堆中生成一个代表这个类的java.lang.Class对象,作为对方法区中这些数据的访问入口
链接(Link)
验证(Verify)
保证被加载类的正确性
文件格式验证,元数据验证,字节码验证,符号引用验证
准备(Prepare)
为类的静态变量分配内存,并将其初始化为默认值
解析(Resolve)
把类中的符号引用转换为直接引用
符号引用:就是一个组符号来描述目标,可以是任何字面量。
直接引用:就是直接指向目标的指针,相对偏移量或一个间接定位到目标的句柄。
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
解析动作主要针对类或接口,字段,类方法,接口方法,方法类型,方法句柄和调用限定符7类符号引用进行。
初始化(Initialize)
对类的静态变量,静态代码块执行初始化操作 执行Clinit方法
类加载器ClassLoader 用来装载Class文件
在装载(Load)阶段,通过类的全限定名获取其定义的二进制字节流,需要借助类装载器完成。
1:Bootstrap ClassLoader 负责加载JAVA_HOME中jre/lib/rt.jar里所有的class或Xbootclassoath选项中指定的jar包。由C++实现,不是ClassLoader子类
2:Extension ClassLoader负责加载java平台中扩展功能的一些jar包,包括'$$JAVA_HOME'中jar/lib/*.jar或-Djava.ext.dirs指定目录下的jar包
3:App ClassLoad负责加载classpath中指定的jar包及Djava.class.path所指定目录下类和jar包
4:Custom ClassLoader通过java.lang.ClassLoader的子类自定义加载class属于应用程序根据自身需要自定义的ClassLoader如tomcat,jboss都会根据j2ee规范自行实现ClassLoader
向上检查,向下委派
运行时数据区(方法区,堆,虚拟机栈,本地方法栈,程序计数器)
方法区(Method Area)
1:方法区是各个线程共享的内存区域,在虚拟机启动时创建
2:虽然java虚拟机规范把方法区描述为堆的一个逻辑部分,但是有一个别名叫Non-Heap,目的与java堆区分开来
3:用于存储已被虚拟机加载的类信息,常量,静态变量,即使编译器编译后的代码等数据
4:当方法区无法满足内存分配需求时,将抛出OutOfMemoryError异常
JVM运行时数据区是一种规范,真正的实现在JDK8中是Metaspace,在JDK6或7中是Perm Space
堆(Heap)
1:java堆是java虚拟机所管理内存中最大的一块,在虚拟机启动时创建,被所有线程共享
2:java对象实例以及数组在堆上分配
虚拟机栈(Java Virtual Machine Stacks)
1:虚拟机栈是一个线程执行的区域,保存着一个线程中方法的调用状态。 一个java线程的运行状态由一个虚拟机栈来保存,所以虚拟机栈肯定是线程私有的,独有的随着线程的创建而创建
2:每一个被线程执行的方法,为该栈中的栈帧,即每个方法对应一个栈帧。调用一个方法,就会向栈中压入一个栈帧;一个方法调用完成,就会把该栈帧从栈中弹出
栈帧:每个栈帧对应一个被调用的方法,可以理解为一个方法的运行空间
每个栈帧中包括局部变量表(Local Variables),操作数栈(Operand Stack),指向运行时常量池的引用(A reference to the run-time constant pool),方法返回地址(Return Address)和附加信息
局部变量表:方法中定义的局部变量以及方法的参数存放在这张表中
局部变量表中的变量不可直接使用,如需要使用的话,必须通过相关指令将其加载至操作数栈中作为操作数使用
操作数栈:以压栈和出栈的方式存储操作数
动态链接:每个栈帧包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态链接(Dynamic Linking)
方法返回地址:当一个方法开发执行后,只有两种方式可以退出,一种是遇到方法返回的字节码指令;一种是遇见异常。并且这个异常没有在方法体内得到处理
对象的创建以及分配过程
FullGC = young GC + Old GC + MetaSpace GC
对象内存布局:Mark Word(一系列的标记位哈希码,分代年龄,锁状态标志等) + Class Pointer(指向对象对应的类元数据的内存地址) + Length(数组对象特有) + 实例数据(包含了对象的所有成员变量,大小由各个变量类型决定) + 对齐填充
强引用:JVM内存管理器从根引用集合(Root Set) 出发遍寻堆中所有到达对象的路径,当到达某对象的任意路径都不含有引用对象时,对这个对象的引用就被称为强引用
软引用:是用来描述一些还有用但是非必须的对象。在系统发生内存溢出异常之前,将会把这些对象列进回收范围中进行二次回收(处理占用内存较大的对象,且生命周期比较长,不频繁使用)
软引用可能会降低应用的运行效率与性能。比如:软引用指向的对象如果初始化很耗时,或者这个对象在进行使用的时候被第三方加了未知的操作
弱引用:与软引用不同在于:GC在进行回收时,需要通过算法检查是否回收软引用对象,而对于Weak引用对象,GC总是进行回收。Weak引用对象会更容易,更快被GC回收
虚引用:为一个对象设置虚引用关联的唯一目的就是能在这个对象被回收时收到一个系统通知。