Java虚拟机(JVM)的类加载机制LLI

JVM的类加载机制?

虚拟机将类数据从Class文件加载到内存,并对数据进行LLI(加载Load、连接Link、初始化Initialization):

加载阶段

通过一个类的全限定名来获取定义此类的二进制字节流;将静态存储结构转化为方法区的运行时数据结构;在内存中生成Class对象,作为类数据的访问入口。

连接阶段

连接阶段包含验证、准备、解析。
验证:包括文件格式验证(Class文件规范,常量池)、元数据验证(是否有父类,final规则)、字节码验证(方法体校验)、符号引用验证。
准备:分配内存并设置类变量初始值。
内存在方法区中分配。内存分配的仅包含类变量(被static修饰的变量),而不包括实例变量,实例变量将在对象实例化时分配在堆中。
解析:将常量池中的符号引用替换为直接引用的过程。

初始化阶段

真正开始执行类中定义的JAVA代码,是执行类构造器()方法(包括所有类变量的赋值动作和静态语句块)的过程。虚拟机第一个被执行的()方法的类肯定是java.lang.Object。

以上步骤中哪一个的顺序可以变化?

解析阶段可以在初始化之后再开始,为了支持Java语言的运行时绑定(也称为动态绑定或晚期绑定)。

什么情况下必须立即对类进行初始化?

1)遇到new、getstatic、putstatic、invokestatic字节码指令时;
2)使用反射来调用类;
3)初始化子类时,父类还未初始化,要立即初始化父类;
4)虚拟机启动时用户指定的main()的类。

什么是对类的被动引用?

1、通过子类引用父类的静态字段,不会导致子类初始化。
2、通过数组定义来引用类,不会触发此类初始化。
3、引用类的常量( public static final String),不会触发定义常量的类的初始化。

加载过程中通过类的全限定名来获取二进制字节流,从哪里获取,怎样获取?

一般从一个Class文件中获取,也可以从ZIP包中、网络中获取,或者运行时计算生成等。
运行时计算生成,使用得最多的就是动态代理技术,在java.lang.reflect.Proxy中,就是用了ProxyGenerator.generateProxyClass来为特定接口生成形式为*$Proxy的代理类的二进制字节流。

连接阶段的准备阶段的类变量初始值设置为多少?

public static int value = 100;
在准备阶段将赋值为0,因为这时候还没有开始执行任何JAVA方法。
除非声明为final,将赋值为100。

类加载器有几个层次?

每一个类加载器,都拥有一个独立的类名称空间。类加载器不同,两个类必定不等。类加载器从上到下有如下几个层次:
Bootstrap ClassLoader:启动类加载器,将$JAVA_HOME/lib目录下的类库加载到虚拟机内存,如rt.jar。
Extension ClassLoader:扩展类加载器,加载$JAVA_HOME/lib/ext目录下的类库。
Application ClassLoader:应用程序类加载器,加载用户类路径ClassPath指定的类库。

什么是双亲委派模型,有什么作用?

双亲委派模型(Parents Delegation Model)指的是类加载时,除了顶层的Bootstrap ClassLoader,其余的类加载器都应有自己的父类加载器(组合关系)。如果一个类加载器收到加载类的请求,必须把请求委派给父类加载器(loadClass)。只有父类无法加载时,此类加载器才会尝试自己加载(findClass)。
使用双亲委派模型,保证了同一个类最终都是由顶层的类加载器加载,不会出现混乱。

参考资料:
《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》 周志明 著

猜你喜欢

转载自blog.csdn.net/weixin_42628594/article/details/84899061