• JVM学习——2——内存加载过程(类加载器)


    类加载器

    一、效果

    class文件被load进内存,同时生成一个Class类的对象,可以用这个Class对象指向这块内容。(class类的对象不是new出来的,是hotspot中C++代码load出来的)
    内存分区,存常量,逻辑上是 method Area 方法区
    1.8之前叫 Perm Generation 永久代
    1.8之后叫 Meta Space
    这两个都是指方法区

    二、 过程

    1. loading  class文件加载到内存
    2. linking
    	1. Verification   校验该文件是否符合class文件标准
    	2. Preparation    把class的静态变量 赋 默认值
    	3. Resolution     常量池里的符号引用转换成实际能直接访问到的地址
    3. Initializing   静态变量赋值为初始值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    三、不同层次的类加载器

    Class类可以用来解析
    class文件的二进制码
    不同的类加载器负责加载不同的class
    String.class.getClassLoader ( )
    !!! 加载器直接不是继承关系,只是层次关系

    1. Bootstrap加载器

    加载核心包;类加载器的范围路径:sun.boot.class.path
    ClassLoader的ClassLoader是Bootstrap加载器,最顶级的加载器 打印为 null
    Bootstrap加载器 负责 加载 JDK中最核心的 jar
    如 runtime.jar
    charset,jar 等等
    是C++实现的
    Bootstrap 引导的意思

    2. Extension加载器

    打印为 ExtClassLoader
    加载扩展包;
    类加载器的范围路径:java.ext.dirs
    加载扩展jar包
    jre/lib/ext/*.jar
    ext目录下的jar 都是扩展包
    或 由 -Djava,ext,dirs指定

    3. App加载器

    打印为 AppLoader
    加载我们自己写的 Java 类;
    类加载器的范围路径:java.class.path
    加载 classpath 指定的内容
    我们自己写的 java 文件都是位于classpath下
    由 App 加载器加载
    APP extend Ext
    APP加载器的父类是Ext加载器
    APP加载器的逻辑上的上一级加载器也是Ext加载器
    但APP加载器的加载器是null
    而Ext没有parent

    4. Custom ClassLoader 加载器

    使用ClassLoader的loadClass(“类路径”)就能把类加载进内存,返回Class类的对象
    Class clazz=Student.class.getClassLoader().loadClass(“com.soft.Student”);
    继承ClassLoader,重写findClass方法
    使用字节流把,class文件load加载到内存
    再使用 defineClass(name,字节流,0,bytes.length) 截取字节流中[0,bytes.lengrh]位置的字节转化为Class类的对象
    // class对象通过反射生成对象,调用方法
    Hello h =(Hello)class.newInstance()
    h.m()
    ======================
    通过自定义ClassLoader可以对class加密
    把生成的class文件 01值 对某个种子值seed 进行异或 ^ 加密
    再seed异或一下就是解密
    int seed=0B10110110
    随便一个种子值都行

    四、 双亲委派

    在这里插入图片描述

    JVM是按需动态加载采用双亲委派机制
    .class 被load进内存的过程
    自定义了类加载器,则先用自定义的类加载器,它内部维护一个缓存,记录这个class是否被加载进来了,如果没加载进来,就回去问App加载器是否加载了,加载就返回结果,
    否则就再往上问,问Extension加载器加载了吗,如果有就返回结果,
    如果没有就继续往上问Bootstrap加载了吗,如果有就返回,没有,就让 Extension加载器加载,如果找到就加载,如果没有找到,就让App加载器去加载,如果找到就加载,
    如果没有,就让custom classloader加载
    还是没找到,就报classNotFound异常
    Bootstrap
    Extension
    App
    Custom ClassLoader
    每个加载器都有自己的缓存
    先自底向上检查 该类是否已经加载 parent 方向
    再自顶向下 进行实际查找和加载child方向

    1.为什么要双亲委派?

    主要是为了安全。次要问题是加载过了,浪费资源;
    如果没有这个机制,可以随便把自己写的类Load进内存,会有安全问题,比如自己写一个类叫 java.lang.String ,把它load进内存,会破坏原有的API

    2. 父加载器

    父加载器不是 “类加载器的加载器”,也不是“类加载器的父类加载器” ,只是上一层次的更高级的加载器;
    双亲委派是一个孩子向父亲的方向,然后父亲再向孩子方向委派的过程

    3. 什么情况下会打破双亲委派?

    重写loadClass方法 ,而不是重写findclass
    什么时候需要打破双亲委派
    JDK1.2之前自定义ClassLoader都必须重写loadClass()
    设置自己线程的classLoader()
    热启动、热部署,为了加载同一类库的不同版本(使用两个同名的类)

    五、编译器

    1. 字节码解释器 bytecode intepreter

    2. 即时编译器 Just In-Time complier ( JIT )

    编译成本地代码,类似.exe

    3. 混合模式

    混合使用 解释器 + 热点代码编译
    起始阶段采用解释执行
    ==========
    热点代码阶段
    多次被调用的方法(方法计数器:监测方法执行频率)
    多次被调用的循环 (循环计数器:监测循环执行频率)
    进行编译
    ==========
    -Xmined 模式为混合模式。开始解释执行,启动速度较快,对热点代码进行检测和编译
    -Xint 使用纯解释模式,启动很快执行稍慢
    -Xcomp 使用纯编译模式,执行很快,启动很慢
    检测热点代码
    -XX:CompileThreshold=10000

    六、JVM的懒加载

    1. 是不是所有的class文件都在启动的时候全部加载呢?

    不是
    java的三种类
    系统类 比如 rt.jar
    拓展类 比如 ext/*.jar
    自己写的类
    加载的时候是先加载核心类,再拓展类,最后自己的类
    按需加载,Student s=new Student()被执行了,会被加载
    Student s2=null就不会加载

    2. 什么时候必须初始化呢?

    初始化子类的时候,父类首先被初始化
    虚拟机启动时,被执行的主类必须初始化
    new 、getstatic、putstatic、invokestatic指令时该类必须初始化
    对类进行反射调用时必须初始化
    动态语言支持java.lang.invoke.MethodHandle解析的结果为REF_getstaticREF_putstaticREF_invokestatic的方法句柄时,该类必须初始化

  • 相关阅读:
    提取多个txt数据并合成excel——例子:与中国建交的国家
    某快递公司Java一面
    Redis - 0、几款可视化工具
    C++字符串详解
    JAVA 链式列表的训练
    RetinaNet-Obj
    window.postMessage - 前端跨域通信
    云原生之深入解析如何使用Vcluster Kubernetes加速开发效率
    主流锂电池保护板BMS蓝牙模块芯片的选型说明之KT6368A双模芯片
    JDK17 新特性
  • 原文地址:https://blog.csdn.net/niTaoTaoa/article/details/126254772