类加载器与类加载过程

类加载器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. 哈希表(HashMap)分析及实现(JAVA)

    转自:http://www.java3z.com/cwbwebhome/article/article8/83560.html?id=4649 探讨Hash表中的一些原理/概念,及根据这些原理/概念, ...

  2. indexedDB数据库创建

    1.首先需要使用使用indexedDB.open()方法,打开数据库 2.通过createObjectStore方法创建表, 创建表之后, 这个表通过createIndex方法创建索引 3.通过tra ...

  3. 高德地图&兴趣点(poi)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...

  4. GUI容器之布局管理器

    布局管理器 布局管理器:frame.setLayout(); 默认值为new flowLayout() 流式布局 frame.setLayout(new FlowLayout(FlowLayout.R ...

  5. Java变量命名规范

    java命名规范 所有方法.变量.类名:见名知意 类成员变量:首字母小写.驼峰原则: 例如:lastName 第一个单词首字母小写,其余首字母大写 局部变量:首字母小写.驼峰原则 类名: 首字母小写. ...

  6. 分布式系列-分布式ID

    一.数据库自增(单实例) 1.方案描述 基于数据库自增ID(auto_increment)利用其来充当分布式ID.实现方式就是用一张表来充当ID生成器,当我们需要ID时,向表中插入一条记录返回主键ID ...

  7. java agent简介

    java agent简介 主要就是两种,一种的方法是premain,一种是agentmain.这两种的区别是: premain是在jvm启动的时候类加载到虚拟机之前执行的 agentmain是可以在j ...

  8. hash类型数据的操作指令

    1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.

  9. java 线程状态 详解

    线程被创建后,有一个生命周期,下图是线程的生命周期详解. java api java.lang.Thread.State 这个枚举中给出了六种线程状态,分别是: 线程状态 导致状态发生条件 NEW(新 ...

  10. python3 用multiprocessing模块传递多个参数

    from datetime import datetime from time import sleep import numpy as np import multiprocessing # fro ...