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 ...
随机推荐
- shiro(二)
public class AuthorizerTest { @Test public void testIsPermitted() { login("classpath:shiro-auth ...
- 多源最短路径,一文搞懂Floyd算法
前言 在图论中,在寻路最短路径中除了Dijkstra算法以外,还有Floyd算法也是非常经典,然而两种算法还是有区别的,Floyd主要计算多源最短路径. 在单源正权值最短路径,我们会用Dijkstra ...
- php实现验证码(数字、字母、汉字)
验证码在表单实现越来越多了,但是用js的写的验证码,总觉得不方便,所以学习了下php实现的验证码.好吧,其实是没有事情干,但是又不想浪费时间,所以学习了下php实现验证码.正所谓,技多不压身.而且,也 ...
- centos7 修改时间
2021-07-28 查看日志时发现系统时间不正确,故修改时间 # 查看当前系统时间 date # 修改当前系统时间 date -s "2021-7-28 17:03:00" # ...
- 前后端数据交互(三)——ajax 封装及调用
有很多框架已经将 ajax 封装,需要的时候只需要调用就好,比如 jquery 是最常用的.我们为什么还需要学习 ajax 的封装呢?首先加强我们对ajax的认识,其次如果只是因为ajax请求需要引入 ...
- 并发编程之:JUC并发控制工具
大家好,我是小黑,一个在互联网苟且偷生的农民工. 在上一期我们讲了Thread.join()方法和CountDownLatch,这两者都可以做到等待一个线程执行完毕之后当前线程继续执行,并且Count ...
- Systemd Journald占用资源过多
journald占用过多磁盘空间 方法一 检查当前journal使用磁盘量 journalctl --disk-usage 清理方法可以采用按照日期清理,或者按照允许保留的容量清理,只保存2天的日志, ...
- 云效x钉钉:让研发工作更简单
云效x钉钉:让研发工作更简单,奔走相告,云效&钉钉集成实现组织架构.成员同步以及消息通知啦! 我们知道云效致力于智能化.安全可追溯.高效.简单.灵活,「云效新一代企业级DevOps平台」阿里云 ...
- Linux--MySQL 日志管理、备份与恢复
MySQL 日志管理.备份与恢复一.MySQL 日志管理二.数据库备份的重要性与分类 1.数据备份的重要性 2.从物理与逻辑的角度,备份分为 3.从数据库的备份策略角度,备份可分为三.常见的备份 ...
- Coreos配置docker镜像加速器
CoreOS配置docker镜像加速器 CoreOS下的Docker配置是通过flannel unit来实现的. 1) 通过命令 systemctl cat docker 可以看出配置文件的默认位置 ...