冯诺依曼计算机体系结构:磁盘的任何文件必须加载到内存才能和cpu进行交互
一、字节码文件
- 来源
java代码通过java虚拟机编译成字节码文件 - 使用
运行程序之前需要将字节码文件加载到jvm虚拟机中
jvm加载字节码文件使用classLoader - 运行
在cpu中运行
二、classloader类加载器
1.来源
- 由JDK中jvm.dll创建类加载器
2.load(加载类,class文件生成对象)
- 类加载器使用io流读取字节码文件,初始化字节码文件的class对象
- 如果有父类还会优先加载父类。
3.Link(初始化静态代码,错误验证,加载类信息)
- 验证语法错误,并为static数据分配内存空间(class不可以用static修饰,除了main’和内部类)
- 将class对象的属性、方法、构造加载到元数据区
4.Init(初始化成员属性、构造方法)
- 类加载完毕,分配了内存空间之后,就会初始化成员属性执行init方法
- 实例化class的时候,首先调用构造方法分配内存,然后jvm立即执行init初始化成员变量,然后执行剩余的构造方法代码,构造方法执行完毕则所有的初始化操作执行完毕;
5.种类(父子关系)
- class-》AppClassLoader-》ExtClassLoader-》BootstrapClassLoader
- BootstrapClassLoader 是由C++编写,是由jvm.dll创建的对象,他是所有类加载器的根
- ExtClassLoader,java可扩展类加载器
6.类加载器优先级
三、类的生命周期
3.1类加载
·····················································································
装载–》链接(验证、准备、解析)–》初始化–》使用–》卸载
·····················································································
3.1.1装载
字节码Class文件–》字节流–》类加载器
将字节流静态存储结构转化为方法区的运行时数据结构,然后生成一个java.lang.Class
对象作为方法区的数据访问入口.
这时候JVM:
方法区中会存放该类的类信息、静态变量、常量
堆会存放经过编译后的java.lang.Class对象
3.2链接
3.2.1验证
跳过验证: Xverify:none //生产环境禁止这样,会让虚拟机不安全,开发环境会让编译速度变得更快
1.字节码文件格式的正确性,例如:JDK版本不一致,格式错误等(会在装载前验证,但是最基本的验证)
2.验证加载后的方法区的储存结构进行验证也叫做元数据的验证,验证语义语法是否符合规范。例如:继承了接口但并未实现接口的抽象方法。
3.字节码验证数据流和控制流分析,(因为jre不信任JDK他不知道这个字节码文件是哪个虚拟机编译出来的)没有参数的运行时检查验证逻辑是否正确。例如:会不会死循环
3.2.2准备
为类变量分配内存,并设置变量的默认初始值。
给static变量和初始化内存,但是final直接在编译阶段就会分配内存并且初始化值,分配到方法区 。不会给普通的成员变量初始化,他会根据类初始化分分配到堆内存。
例如:static int ,准备阶段会初始化默认为0,如果使用final static int = 2则会直接赋值2,这些局限于基本数据类型和String,这些实际的值只能使用常量池中的值。
static变量有一些是在构造器中幅值,有些是准备阶段直接初始化成这个值,例如final static
3.2.3解析
常量池中的符号引用转变为直接引用。
例如:两个class类 a、b ,a中有一个变量为b类型,那么b会在堆中有一个编译后class对象,那么a中的b符号引用就会在解析时对应到b的堆class对象。
3.3初始化
当一个类要使用则需要new,也就是执行类构造器。
在这里多说一下,在准备阶段初始化了static变量和static静态代码块,然后new对象时,会执行构造方法初始化成员变量
3.4使用
- new对象后,调用方法
- class类名.static方法名引用
- 路径地址反射使用
- 启动类自动会被初始化
3.5卸载
当类的所有实例也就是说堆内存的class对象没有任何栈使用则会被卸载,
卸载会在方法区垃圾回收清空类信息
参考资料
- www.bilibili.com/video/BV13t…
- java核心卷