虚拟机类加载过程

2021-07-15  本文已影响0人  winter818
image2021-4-7_16-34-38.png
  1. 方法区与Java堆一样,线程共享的数据区域,用于存储已经被类加载器加载的类信息,常量,静态变量,编译器编译后的代码
  2. 在HotSpot虚拟机上方法区属于永久代,Dalvik,Art上不确定
  3. 虚拟机规范中明确过:可以不对方法区进行垃圾收集,在方法区进行回收性价比较低,在堆中进行垃圾回收一般可以回收75%-95%的空间,但是方法区远低于此
  4. 回收类需要满足三个条件:
    1. 该类的所有对象都已经被回收
    2. 该类的类加载器已经被回收
    3. 该类对应的Class对象没有任何地方被引用,无法在任何地方通过反射回去该类的方法
image2021-4-7_17-31-48.png

class文件格式

image2021-4-7_19-55-20.png

魔数:CAFEABBE,代表了是一个可执行的java文件

此版本号,主版本号,常量池,访问标志,类信息,父类信息,接口数,接口信息,,字段表合计,方法表合集,属性表合集

  1. 字符串常量池,Java1.6存放在方法区,Java1.7存放在堆
  2. class常量池包含了字面量和符号引用
    1. 字面量就是基本类型和被final修饰的常量
    2. 符号引用是类的全限定名,字段描述,方法描述
image2021-4-7_16-40-53.png

加载

加载阶段,虚拟机完成3件事情

  1. 通过一个类的全限定名来获取定义此类的二进制字节流
  2. 将这个字节流所代表的的静态存储结构转化为方法区运行时数据结构
  3. 内存中生成一个代表这个了的Class对象,存储到方法区

加载来源可以是zip,jar,dex,网络

动态代理类ProxyGenerator.generateProxyClass给特定的接口生成形式为$Proxy的代理类的二进制字节流

对于数组不适用类加载器去加载,数组类型是有虚拟机直接创建 、

Classloader

BootClassLoader: android系统启动创建

PathClassLoader: 加载已安装的Apk文件

参数:String dexPath, String libraryPath, ClassLoader parent

DexClassLoader:加载未安装的apk,jar,dex的文件:

参数:String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent

验证

主要是确定class文件的字节流中保管的信息符合当前虚拟机的要求,不会危害虚拟机的安全

文件格式验证

1. 文件格式验证是否以0xFAFEBABE开头

2. 主次版本号是否处于合理范围

3. 常量池中是否有不支持的常量类型

4. 编码是否正确

元数据验证

1. 这个类是否有父类,Object除外

2. 这个类是否继成了不允许被继承的类,final修饰的类

3. 如果继承了抽象类有abstract方法实现

验证字节码

1. 目的是保证被验证的类运行时不会危害虚拟机的安全

2. 保证任意时刻操作数栈类型与代码执行序列能够配合工作,不会出现操作数栈里放了一个int,使用的时候按照long类型加载到本地变量表

3. 保证类型转换的有效性,例如可以把子赋值给父类但是不能把父类赋值给子类

准备

准备阶段是为类变量分配内存设置类变量初始值,初始值是数据类型的零值

public static int value = 123;

经过准备阶段后值是0不是123,准备阶段没有执行任何Java代码。赋值的指令putstatic是在类的构造器init方法中,所以赋值实在初始化阶段

public static final value = 123准备阶段后则值为123,如果类字段的字段属性表中有ConstantValue属性准备阶段会直接初始化

解析

解析阶段是把类的常量池中符号引用解析成直接引用,符号引用是用描述所引用的目标,符号可以是字面量要能够准确定位的引用目标,直接引用是可以是目标的地址

初始化

虚拟机规范规定有且只有5个时机必须对类进行初始化,初次之外的所有引用类的方式不会初始化

  1. 遇到new,getstatic,putstatic,invokestatic指令的时候,分别对应的操作是new关键字实例化对象,读取,设置静态属性 。 但是被final修饰,已经在编译时期放入常量池的除外,调用静态方法

2. 通过反射对类进行反射调用的时候

3. 初始化一个类的时候如果父类没有初始化则先初始化

4. 当虚拟机启动时用户指定一个入口类,包含main方法的类

5. Jdk1.7动态语言MethodHandle解析结果REF_getstatic,REF_putsttaic,REF_invokestatic的方法句柄对应的类没有初始化则先初始化

image2021-4-9_15-42-40.png image2021-4-9_15-43-20.png

类的初始化方法<cinit>是编译器自动生成,cinit不需要显示调用父类的构造器,虚拟机会在子类cinit之前父类的cinit先调用,虚拟机会保证类的<clinit>多线程环境中加锁,同步,多个线程同时初始化类只有一个线程执行,其他线程等待,一个类的初始化操作只会执行一次,同一个类加载器一个类只会初始化一次

上一篇下一篇

猜你喜欢

热点阅读