文章目录
JVM工作过程
JVM运行的过程涉及三个子系统:
- 类装载子系统(Class loader SubSys)
- 运行时数据区(Running Data Areas)
- 执行引擎(Execution Engine)
类加载子系统
-作用是将字节码文件加载到JVM中,在类第一次被使用的时候,需要初始化文件。
-
装载:功能就是加载类,使用到了三个类加载器。
Bootstrap ClassLoader 启动类加载器
Extension ClassLoader执行类加载器
Application ClassLoader应用来加载器 -
链接:
验证:字节码验证器将验证生成字节码是否正确,如果验证失败,将得到验证错误。
准备:对于所有的静态变量,进行i分配内存并给默认值分配内存,并给默认值null
解析:将所有的符号内存引用替换为方法区的原始引用初始化,静态变量将被赋予原始值,静态代码块将被执行。
运行时数据区域
- 方法区:类级别数据、静态变量的应用,线程共享。
- 堆区:对象及其实例变量和数据的存储位置,线程共享。
- 栈区:程序运行过程中使用栈区,线程私有。
- 本地方法栈:保存本地方法的信息,调用JNI(java 本地接口),线程私有。
- 程序计数器:线程私有。
执行引擎
- 将分配给运行时数据区域的字节码将由执行引擎来执行,执行引擎读取字节码并逐个进行执行。
类加载器
负责将字节码加载到内存中。
2. Bootstrap ClassLoader:启动类加载器 负责加载 JAVA_HOME的jre/lib/rt.jar里面所有的class
3. Extension ClassLoader:扩展类加载器
负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中除jre/lib/*.jar或者-DJava.ext.dirs=XXX指定路径下的jar包
4. Application ClassLoader:应用类加载器 负责加载classpath中指定的jar和目录中的class
双亲委派模型
双亲委派模型来加载类的过程:
5. 当前类加载器会从自己已经加载的类中查询此类是否已经加载,如果已经加载则返回原来已经加载的类。
6. 如果没有找到,就会委派父亲记载其加载,父类加载器采用同样的策略,查看自己已经加载的类是否包含这个类,有则返回,没有的话就委托父类,知道委托给启动类加载器为止。因为启动类加载器的父类为空,到启动类加载器就不会网上进行委托。
7. 如果启动类加载器加载失败,就会使用扩展类加载器进行加载,继续失败则使用应用类加载器来进行加载,继续失败就会抛出一个异常:ClassNotfoundException
双亲委派的优点
- 安全性,比卖你用户自己编写的类动态替换java的一些核心类,如果不采用双亲委派模型的加载方式进行类的加载工作,那我们就可以随时使用自定义的类来动态代替java核心API中定义的类。例如:如果黑客将“病毒代码”植入到自定义的String类当中,随后类加载器将自定义的String类加载到JVM上,那么此时就会对JVM产生意想不到“病毒攻击”。而双亲委派的这种加载方式就会避免这种情况,因为String类已经在启动时就被应用类加载器进行加载。
- 避免类的重复加载。 JVM判定两个类是否时同一个类,不仅仅根据类名是否相同进行判定,还需要判断加载该类的类加载器是否时同一个类加载器,相同的class文件被不同的类加载器加载得到的结果就是两个不同的类。