zoukankan      html  css  js  c++  java
  • JVM系列【3】Class文件加载过程

    JVM系列笔记目录

    • 虚拟机的基础概念
    • class文件结构
    • class文件加载过程
    • jvm内存模型
    • JVM常用指令
    • GC与调优

    Class文件加载过程

    JVM加载Class文件主要分3个过程:Loading 、Linking、Initialzing

    1.Loading

    Loading的过程就是通过类加载器将.class文件加载到jvm内存中过程。需要理解双亲委派机制、类加载器ClassLoader,加载过程如下。
    file

    ClassLoader

    不同的类加载器加载范围不一样,以Java8中的为例。

    • BootClassLoader 加载范围sun.boot.class.paht
    • ExtClassLoader 加载范围java.ext.dirs
    • AppClassLoader 加载范围java.class.path
    • CustomClassLoader 可自定义加载范围

    前三个加载器来自JDK的Launcher类,三个ClassLoader作为Launcher的内部类,感兴趣可以查看下源码。
    file
    开发者也可以自定义的ClassLoader,自定义记载范围。

    双亲委派机制

    自底向上检查该类是否已经加载,parent方向;自顶向下进行类的实际查找和加载,child方向。
    类的加载遵循双亲委派机制,主要是出于安全的考虑。双亲委派机制是如何实现的,下面源码会解释。
    file
    注意:双亲委派中存在所谓的父加载器并不是加载器的加载器,只是翻译的问题,别混淆了类的继承概念。

    ClassLoader源码

    file
    ClassLoader源码中比较重要的一个函数是loadClass(),执行过程是:findLoadedClass()->parrent.loadClass()->findClass(),第一步是自底向上查询是否已经加载,第二步是自顶向下查找加载类。这里就规定或是说实现了双亲委派机制。详细见ClassLoader的源码。

    自定义ClassLoader

    如何自定义ClassLoader?可以继承ClassLoader类,重新自己的findClass(),在里面调用defineClass()来实现自定义加载特定范围的类。

    如何打破双亲委派机制,哪种情形下打破过?

    从上面的ClassLoader源码中大概能看出是如何实现了双亲委派机制的,从这入手可以通过2种方式打破该机制:

    1. super(parent)指定parent会打破该机制
    2. 自定义ClassLoader重写loadClass()也可以打破

    何时打破过?双亲委派机制并不是不能打破,某些特殊场景下也会选择打破该机制。

    1. JDK 1.2之前,自定义ClassLoader必须重写loadClass(),打破过。
    2. 线程ThreadContextClassLoader可以实现基础类调用实现类代码,通过thread.setContextClassLoader指定。
    3. 热启动热部署,如tomcat都有自己模块指定的classloader,可以加载同一类库的不同版本。

    Class执行方式

    Class执行方式分为3种:解释执行、编译执行、混合执行,各有优缺点,可通过参数指定。

    • 1.解释执行:使用bytecode intepreter 解释器解释执行,该模式启动很快,执行稍慢,可通过-Xint参数指定该模式。
    • 2.编译执行:使用 Just in time Complier JIT编译器编译执行,该模式执行很快,编译很慢,可通过-Xcomp参数指定该模式。
    • 3.混合执行:默认的模式,解释器+热点代码编译,开始解释执行,启动较快,对热点代码进行实时监测和编译成本地代码执行,可通过-Xmixed参数指定该模式。

    热点代码监测:多次被调用的方法用方法计数器,多次被调用的循环用循环计数器,可通过参数-XX:CompileThreshold = 10000指定触发JIT编译的阈值。

    2.Linking

    Linking链接的过程分3个阶段:Vertification、Preparation、Resolution。

    • Vertification: 验证Class文件是否符合JVM规定。
    • Preparation:给静态成员变量赋默认值
    • Resolution:将类、方法、属性等符号引用解释为直接引用;常量池中的各种符号引用解释为指针、偏移量等内存地址的直接引用

    3. Initializing

    调用初始化代码clint,给静态成员变量赋初始值。

    这里可以了解下必须初始化的5种情况:

    • new getstatic putstatic invokestatic指令,访问final变量除外
    • java.lang.reflect对类进行反射调用时
    • 初始化子类的时候,父类必须初始化
    • 虚拟机启动时,被执行的主类必须初始化
    • 动态语言支持java.lang.invoke.MethodHandler解释的结果为REF_getstatic REF_putstatic REF_invokestatic的方法句柄时,该类必须初始化。

    4.总结思考

    设计模式中单例模式的双重检查的实现,INSTANCE是否需要加valatile

    public class Mgr06 {
        // 是否需要加volatile?
        private static volatile Mgr06 INSTANCE;
    
        private Mgr06() {
        }
    
        public static Mgr06 getInstance() {
            if (INSTANCE == null) {
                //双重检查
                synchronized (Mgr06.class) {
                    if(INSTANCE == null) {
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        // new 了对象,不为null,但未完成变量的初始化复制,对象处于半初始化状					态,其它线程有可能取到半初始化的对象。
                        INSTANCE = new Mgr06();
                    }
                }
            }
            return INSTANCE;
        }
    }
    

    个人认为是需要加的。思考方向, class文件load到内存,给静态变量赋默认值,再赋初始值,new 对象的时候,首先要申请内存空间,然后给成员变量赋默认值,接下来给成员变量赋初始值,这个过程中对象有可能处于半初始化状态,多线程并发下别的线程有可能取到半初始化的对象,加volatile可保证线程的可见性。

    知识分享,转载请注明出处。学无先后,达者为先!

  • 相关阅读:
    java.lang.NoSuchMethodError
    asm相关内容想下载(包括 jar 包)
    Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/objectweb/asm/Type
    用Navicat连接mysql报错:2003-Can't connect to MySql server on '10.100.0.109'(10039)
    The type java.lang.reflect.AnnotatedElement cannot be resolved. It is indirectly referenced from required .class files
    The type java.lang.CharSequence cannot be resolved. It is indirectly referenced from required .class files
    交通测速方式
    卡口和电子警察的区别
    Myeclipse连接Mysql数据库时报错:Error while performing database login with the pro driver:unable
    在window上安装mysql
  • 原文地址:https://www.cnblogs.com/kongbubihai/p/13794289.html
Copyright © 2011-2022 走看看