JVM学习笔记——类加载器与类加载过程
类加载器与类加载过程
类加载器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学习笔记——类加载器与类加载过程的更多相关文章
- 【JVM学习笔记】线程上下文类加载器
有许多地方能够看到线程上下文类加载的设置,比如在sun.misc.Launcher类的构造方法中,能够看到如下代码 先写一个例子建立感性认识 public class Test { public st ...
- JVM学习笔记:虚拟机的类加载机制
JVM类加载机制分两部分来总结: (1)类加载过程 (2)类加载器 一.JVM类加载过程 类的加载过程:加载 →连接(验证 → 准备 → 解析)→ 初始化. 类的生命周期:加载 →连接(验证 → 准备 ...
- JVM学习笔记五:虚拟机类加载机制
类加载生命周期 类加载生命周期:加载.验证.准备.解析.初始化.使用.卸载 类加载或初始化过程什么时候开始? 遇到new.getstatic.putstatic或invokestatic这4条字节码指 ...
- JVM学习笔记——类加载过程
JVM学习笔记——类加载过程 类加载模型——双亲委派模型(Parents Delegation Model)也可称为“溯源委派加载模型” Java的类加载器是一个运行时核心基础设施模块,主要是启动之初 ...
- jvm学习笔记:类加载过程
类加载器子系统 类加载器的作用是加载class文件到内存 加载阶段->链接阶段->初始化阶段 ClassLoader只负责class文件的加载,至于是否能够运行由执行引擎判断 加载的类信息 ...
- JVM学习笔记-第七章-虚拟机类加载机制
JVM学习笔记-第七章-虚拟机类加载机制 7.1 概述 Java虚拟机描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被 ...
- JVM学习笔记——类加载和字节码技术篇
JVM学习笔记--类加载和字节码技术篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的类加载和字节码技术部分 我们会分为以下几部分进行介绍: 类文件结构 字节码指令 编译期处理 类 ...
- JVM学习笔记之类加载机制【八】
一.类加载时机 1.1 触发类初始化的六个场景: 加载? 1.遇到new.getstatic.putstatic或invokestatic这四条字节码指令时 如果类型没有进行过初始化,则需要先触发其初 ...
- JVM(一)类加载器与类加载过程
JVM是面试必面的一个知识点,也是高级程序员必备的一个技能.以下是JVM整体核心内容,包括类加载系统,运行时数据区内部结构,执行引擎,本地方法接口. 首先来学习类的加载器,虚拟机把描述类的数据从Cla ...
随机推荐
- 第13篇-通过InterpreterCodelet存储机器指令片段
在TemplateInterpreterGenerator::generate_all()函数中生成了许多字节码指令以及一些虚拟机辅助执行的机器指令片段,例如生成空指针异常抛出入口的实现如下: { C ...
- rasa 如何写一个故事
设计故事 在设计故事时,需要考虑两组对话交互:快乐路径和不快乐路径.快乐路径描述用户何时按照您的预期遵循对话流程,并在出现提示时始终提供必要的信息.然而,用户经常会因为问题.闲聊或其他问题而偏离愉快的 ...
- Spring boot中注册Servlet
Spring boot中注册Servlet 如何在spring boot项目中注册Servlet呢? 如何在spring boot项目中注册Servlet呢? 由于没有web.xml,无法直接在xml ...
- kubernetes使用jenkins Pipeline 部署Nginx
文章原文 环境需求 kubernetes 未安装参考使用kubeadm安装kubernetes 1.21 jenkins github/gitee/gitlab 静态页面 镜像仓库(我使用的 hub. ...
- Systemd Journald占用资源过多
journald占用过多磁盘空间 方法一 检查当前journal使用磁盘量 journalctl --disk-usage 清理方法可以采用按照日期清理,或者按照允许保留的容量清理,只保存2天的日志, ...
- ELK数据迁移,ES快照备份迁移
通过curl命令或者kibana快照备份,恢复的方式进行数据迁移 环境介绍 之前创建的ELK 因为VPC环境的问题,需要对ELK从新部署,但是还需要保留现有的数据,于是便有了这篇文档. 10.0.20 ...
- Ordering the Soldiers 题解
CodeChef:ORDERS 简化题意: \(n\) 个人排队,给定每个人需要向左移动几个,求最终排列. 即还原逆序对. 错误想法 既然知道每个人向左移动 \(a_i\) 个,那就相当于让他的排名 ...
- www迁移
www迁移主要就是2部分: 1)官网页面架构,即 ./drupal/index.php 2)官网图片,即 ./drupal/assets/ 目录下的文件 1. 在ubuntu上搭建基础v1.0环境 2 ...
- C#中的“等待窗体”对话框
这篇文章向您展示了如何在c#.net Windows窗体应用程序中创建一个等待窗体对话框.创建一个新表单,然后输入您的表单名称为frmWaitForm.接下来,将Label,Progress Bar控 ...
- DOM对象入门
1.概念 2.script最好是放在后面,等html的文档内容加载完毕,不然获取不到 3.事件基本操作 第一种绑定事件html和js耦合度高,用第二种 4.灯开关事件使用