当前位置: 首页 > 科技观察

JVM系列—Class文件加载流程

时间:2023-03-12 02:02:44 科技观察

JVM系列笔记目录虚拟机基本概念class文件结构class文件加载流程jvm内存模型JVM常用指令GC与调优Class文件加载流程JVM加载class文件主要分为3个过程:Loading,Linking,Initialzing的过程1.LoadingLoading是通过类加载器将.class文件加载到jvm内存中的过程。有必要了解双亲委托机制和类加载器ClassLoader。加载过程如下。ClassLoader不同的类加载器加载范围不同,以Java8为例。BootClassLoader加载范围sun.boot.class.pahtExtClassLoader加载范围java.ext.dirsAppClassLoader加载范围java.class.pathCustomClassLoader可以自定义加载范围前三个加载器来自JDK的Launcher类,三个ClassLoader是JDK的内部类启动器。有兴趣的可以查看源码。开发者还可以自定义ClassLoader,自定义录制范围。双亲委托机制自下而上,父方向检查类是否已经加载;类的实际搜索和加载自上而下,子方向。类加载遵循双亲委派机制,主要是出于安全考虑。parentdelegation机制是如何实现的,在下面的源码中会有说明。注意:parentaldelegation中所谓的parentloader,并不是loader的loader,而是一个翻译问题。不要混淆类继承的概念。ClassLoader源代码中比较重要的函数之一是loadClass()。执行过程为:findLoadedClass()->parrent.loadClass()->findClass()。第一步是检查它是否已经自下而上加载。第二步是自上而下搜索加载类。这里规定或实现了双亲委托机制。具体参见ClassLoader的源码。自定义ClassLoader如何自定义ClassLoader?可以继承ClassLoader类,重新创建自己的findClass(),并在其中调用defineClass(),实现自定义加载特定范围的类。双亲委派机制如何被打破,又是在什么情况下被打破的?从上面的ClassLoader源码中,我们可以大致看出双亲委托机制是如何实现的。从这里开始,我们可以通过两种方式打破该机制:super(parent)指定父级将打破该机制。CustomClassLoaderoverridesloadClass()它能坏吗它什么时候坏过?双亲委托机制也不是不能破解,在一些特殊场景下也会选择破解机制。在JDK1.2之前,自定义ClassLoader必须覆盖loadClass(),这也失败了。线程ThreadContextClassLoader可以实现基础类调用实现类代码,由thread.setContextClassLoader指定。热启动热部署,比如tomcat自带模块指定的classloader,可以加载同一个类库的不同版本。类的执行方式类的执行方式分为三种:解释执行、编译执行和混合执行。各有优缺点,可以通过参数指定。1.解释执行:使用bytecodeintepreter解释器解释执行。这种模式启动很快,执行速度稍慢。您可以通过-Xint参数指定此模式。2.编译执行:使用JustintimeComplierJIT编译器编译执行。此模式执行速度非常快,但编译速度非常慢。您可以通过-Xcomp参数指定此模式。3.混合执行:默认模式,解释器+热点代码编译,启动解释执行,启动速度更快,实时监控热点代码并编译成本地代码执行,可以通过-Xmixed参数指定该模式.热代码监控:方法计数器用于调用多次的方法,循环计数器用于调用多次的循环。可通过参数-XX:CompileThreshold=10000指定触发JIT编译的阈值。2.LinkingLinking链接过程分为三个阶段:Verification、Preparation、Resolution。Vertification:验证Class文件是否符合JVM规定。准备工作:为静态成员变量赋默认值解决方法:将类、方法、属性等符号引用解释为直接引用;常量池中的各种符号引用被解释为对内存地址的直接引用,例如指针和偏移量3.初始化调用初始化代码clint为静态成员变量赋初值。这里可以理解5种必须初始化的情况:newgetstaticputstaticinvokestatic指令,访问final变量除外java.lang.主类必须初始化动态语言支持java.lang.invoke.MethodHandler当解释结果为REF_getstaticREF_putstaticREF_invokestatic方法句柄时,必须初始化该类。4、总结思考单例模式的doublecheck在设计模式中的实现。INSTANCE需要加valatile吗?publicclassMgr06{//是否需要添加volatile?privatestaticvolatileMgr06INSTANCE;privateMgr06(){}publicstaticMgr06getInstance(){if(INSTANCE==null){//doublechecksynchronized(Mgr06.class){if(INSTANCE==null){try{Thread.sleep(1);}catch(InterruptedExceptione){e.printStackTrace();}//新对象不为null,但是变量的初始化拷贝还没有完成,对象处于半初始化状态state,其他线程可能会得到half初始化的对象。INSTANCE=newMgr06();}}}returnINSTANCE;}}复制我个人认为需要添加的代码。想好方向,把class文件加载到内存中,给静态变量赋默认值,然后赋初值。创建新对象时,先申请内存空间,然后给成员变量赋默认值,再给成员变量赋初值。在此过程中,对象可能处于半初始化状态,其他线程可能会以多个线程并发获取半初始化对象。加入volatile可以保证线程的可见性。