类加载器与类加载过程

类加载器ClassLoader

  类加载器 ClassLoader 用于把 class 文件装载进内存。

  • 启动类加载器(Bootstrap ClassLoader)

    • 这个类加载使用C/C++ 语言实现,嵌套在 JVM 内部

    • 用来加载 java 的核心类库,(rt.jar,resource.jar 或 sun.boot.class.path)路径下面的内容,提供JVM自身需要的类

    • 并不继承于 java.lang.ClassLoader,启动类加载器没有父类加载器

    • 加载 扩展类加载器 和 应用程序加载器 并指定它们的父类加载器

    • 出于安全考虑,Bootstrap 启动类加载器只加载包名为 java,javax,sun 等开头的类

  • 扩展类加载器 (Extension ClassLoader)

    • java 语言编写,有 Launcher 的内部类

    • 派生于 ClassLoader 类

    • 父类加载器为启动类加载器

    • 从 java.ext.dirs 系统属性所指定的目录中加载类库,或从 JDK 的安装目录 jre/lib/ext 下加载类库,如果用户创建的 jar 放在此目录,也会由扩展类加载器加载

  • 应用程序加载器(Application ClassLoader)

    • java 语言编写,由 Launcher 的内部类

    • 派生于 ClassLoader 类

    • 父类加载器为扩展类加载器

    • 负责加载环境变量 classpath 或系统属性,java.class.path 指定路径下的类库

    • 该类加载是程序中默认的类加载器,一般来说,Java应用类都是由它来完成

  • 用户自定义类加载器(User Defined ClassLoader)

    • 自定义类加载器通常需要继承 ClassLoader

    • 哪些情况下需要自定义类加载器:

      • 隔离加载类,在某些框架内进行中间件与应用的模块隔离,把类加载到不同环境

      • 修改类加载的方式

      • 扩展加载源

      • 防止源码泄漏,Java 代码容易编译和篡改,可以进行编译加密

类加载机制

  JVM 的类加载机制有三种,目前 HotSpot 默认使用双亲委派机制:

  • 全盘负责机制:当一个类加载器负责加载某个类时,若没有显示使用另外一个类加载器来载入,则默认该类所依赖和引用的其他类也由该类加载器负责载入

  • 双亲委派机制:先委托父类装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类

  • 缓存机制:缓存机制会缓存所有加载过的类,当程序需要使用某个类时,类加载器先从缓存区中搜寻该类,只有缓存区中不存在该类时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中

双亲委派机制 

  当类加载器收到了类加载请求时,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归。

  本质:规定了类加载的顺序,引导类加载器先加载,若加载不到,由扩展类加载器加载,再加载不到,由应用程序加载器加载。

优点:

  • 可以避免重复加载,当父类加载器已经加载了该类的时候,就没有必要再加载一次
  • 安全性更高,采用双亲委派机制 Java 核心 api 库不会被随意篡改,假设通过网络传递一个名为 java.lang.Integer 的类,通过双亲委托模式传递到启动类加载器,而启动类加载器在核心 Java api 发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的 java.lang.Integer,而直接返回已加载过的 Integer.class

缺点:

  顶层的 ClassLoader 无法访问底层的 ClassLoader 所加载的类,系统类访问应用类就出现了问题。比如,在系统类中提供了一个接口,该接口需要在应用类中得以实现,该接口还绑定一个工厂方法,用于创建该接口的实例,而接口和工厂方法都在这个启动类加载器,这时,就出现了该工厂无法创建由应用类加载器的应用实例问题

  Java 虚拟机规范并没有明确要求类加载器的加载机制一定使用双亲委派模型,只是建议采用这种方式。

沙箱安全机制

  Java 安全模型的核心就是 Java 沙箱,沙箱是一个限制程序运行的环境,沙箱机制就是将Java 代码限定在虚拟机特定的运行范围中, 并且严格限制代码对本地系统资源的访问,通过这样的措施来保证对代码的有效隔离,防止对本地系统造成破坏。沙箱主要限制系统资源访问。所有的 Java 程序都可以指定沙箱,可以定制安全策略。

  在 JDK 1.6 的最新安全模型中,引入了域(Domain) 的概念,虚拟机会把所有代码加载到不同的系统域和应用域中,系统域负责与关键资源交互,应用域通过系统域的代理实现对资源的访问。不同的受保护域,对应不同的权限。本质是把程序划分到不同的权限组中执行

优点:

  • 保证程序安全

  • 保护 Java 原生 JDK 代码不被篡改

组成沙箱的基本组件:

  • 字节码校验器:在类加载的过程中进行字节码校验,确保 Java 类文件的语言规范,核心类不进行字节码校验

  • 类装载器:类装载器对沙箱的作用

    • 防止恶意代码干涉其他代码(双亲委派机制)

    • 保护被信任类库的边界(双亲委派机制)

    • 将代码归入保护域,确定代码可以执行那些操作(沙箱安全机制)

类加载过程

  1. 加载

  将类的 class 文件读入内存,并将这些静态数据转换成方法区的运行时数据结构,然后创建一个代表这个类的 java.lang.Class 对象

类加载器加载 Class 流程如下:

  2. 链接

  将类的二进制数据合并到 JRE 中

    • 验证:确保加载信息符合 JVM 规范,保证虚拟机安全

    • 准备:为类的静态变量在方法区分配内存,并设置类变量默认初始值

    • 解析:将虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)

  3. 初始化

  初始化完全由虚拟机主导和控制。到了初始化阶段才真正执行 Java 代码。类初始化的主要工作是为静态变量赋程序设定的初值。也就是执行类构造器 <clinit>()方法的过程

    • 当初始化一个类时,如其父类还未初始化,则需先触发父类初始化

    • 虚拟机负责<clinit>()方法在多线程中的安全性和同步问题

类的主动引用与被动引用

  • 类的主动引用一定会发生类的初始化

    • 虚拟机启动时,启动类被初始化,如 main 方法所在的类

    • 创建类的实例,new 一个对象

    • 调用类的静态成员(除 final 常量)和静态方法

    • 反射,使用 java.lang.reflect 包的方法对类进行反射调用

    • 初始化一个父类未被初始化的子类,先初始化父类

  • 类的被动引用不会发生类的初始化

    • 访问静态域时,只有当声明这个域的类时才会发生初始化。eg:当子类引用父类的静态变量时不会发生初始化

    • 通过数组定义类引用

    • 引用常量不会发生该类的初始化,常量在链接阶段就存入常量池中

JVM学习笔记——类加载器与类加载过程的更多相关文章

  1. 【JVM学习笔记】线程上下文类加载器

    有许多地方能够看到线程上下文类加载的设置,比如在sun.misc.Launcher类的构造方法中,能够看到如下代码 先写一个例子建立感性认识 public class Test { public st ...

  2. JVM学习笔记:虚拟机的类加载机制

    JVM类加载机制分两部分来总结: (1)类加载过程 (2)类加载器 一.JVM类加载过程 类的加载过程:加载 →连接(验证 → 准备 → 解析)→ 初始化. 类的生命周期:加载 →连接(验证 → 准备 ...

  3. JVM学习笔记五:虚拟机类加载机制

    类加载生命周期 类加载生命周期:加载.验证.准备.解析.初始化.使用.卸载 类加载或初始化过程什么时候开始? 遇到new.getstatic.putstatic或invokestatic这4条字节码指 ...

  4. JVM学习笔记——类加载过程

    JVM学习笔记——类加载过程 类加载模型——双亲委派模型(Parents Delegation Model)也可称为“溯源委派加载模型” Java的类加载器是一个运行时核心基础设施模块,主要是启动之初 ...

  5. jvm学习笔记:类加载过程

    类加载器子系统 类加载器的作用是加载class文件到内存 加载阶段->链接阶段->初始化阶段 ClassLoader只负责class文件的加载,至于是否能够运行由执行引擎判断 加载的类信息 ...

  6. JVM学习笔记-第七章-虚拟机类加载机制

    JVM学习笔记-第七章-虚拟机类加载机制 7.1 概述 Java虚拟机描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被 ...

  7. JVM学习笔记——类加载和字节码技术篇

    JVM学习笔记--类加载和字节码技术篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的类加载和字节码技术部分 我们会分为以下几部分进行介绍: 类文件结构 字节码指令 编译期处理 类 ...

  8. JVM学习笔记之类加载机制【八】

    一.类加载时机 1.1 触发类初始化的六个场景: 加载? 1.遇到new.getstatic.putstatic或invokestatic这四条字节码指令时 如果类型没有进行过初始化,则需要先触发其初 ...

  9. JVM(一)类加载器与类加载过程

    JVM是面试必面的一个知识点,也是高级程序员必备的一个技能.以下是JVM整体核心内容,包括类加载系统,运行时数据区内部结构,执行引擎,本地方法接口. 首先来学习类的加载器,虚拟机把描述类的数据从Cla ...

随机推荐

  1. Element form表单方法resetFields无效

    之前遇到resetFields无效时都是自己手动用this.ruleForm = Object.assign({}, this.ruleForm, this.$options.data().ruleF ...

  2. pgsql日期树数值类型指定与介绍

    http://www.postgres.cn/docs/9.3/datatype-net-types.html#DATATYPE-INET  文档有详细的pgsql介绍 使用案例: SELECT to ...

  3. linux下查看磁盘使用内存及清除日志内存

    1.查看磁盘内存 df -h 2.清理日志内存 echo "">catalina.out

  4. 阿里云服务器部署mongodb

    在阿里云上买了个服务器,部署mongodb遇到一些坑,解决办法也是从网上搜集而来,把零零碎碎的整理记录一下. 服务器是:Alibaba Cloud Linux 下载安装 mongodb官网下载实在是太 ...

  5. Python语法之函数、引用和装饰器

    所谓函数,就是把具有独立功能的代码块组织成为一个小模块,在需要的时候调用 函数是带名字的代码块,用于完成具体的工作 需要在程序中多次执行同一项任务时,你无需反复编写完成该任务的代码,而只需调用该 任务 ...

  6. PyQT5基础布局管理

    绝对定位布局 使用move(x, y)可以对窗口进行布局,以窗口左上角为原点,向右为 x 轴正方向,向下为 y 轴正方向,移动(x,y); import sys from PyQt5.QtGui im ...

  7. Python脚本导出AWS EC2资源清单

    环境需求 单位现在每隔一段时间需要核对一下 AWS 正在运行的 EC2 资源清单,为了避免核对失误以及重复性的工作,打算用脚本来解决这一重复性的工作.大概思路为 通过 AWS AK.SK 来索取 AW ...

  8. adb 常用命令大全(3)- 查看手机设备信息

    查看手机型号 adb shell getprop ro.product.model 查看电池状况 adb shell dumpsys battery 其中 scale 代表最大电量,level 代表当 ...

  9. 通过JDK动态代理实现 Spring AOP

    1.新建一个目标类 接口:public interface IUserService //切面编程 public void addUser(); public void updateUser( ); ...

  10. 如何实现自定义sk_buff数据包并提交协议栈

    目录 一.自定义数据包的封装流程 1. 分配skb 2.初始定位(skb_reserve) 3.拷贝数据(skb_push / skb_pull / skb_put / ) 4.设置传输层头部 5.设 ...