1.内存结构概述

简图

详细

2.类加载器与类加载的过程

  • 类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识[CA FE BA BY 字节码文件标识]

  • ClassLoader只负责class文件的加载,至于是否可以运行,则是由Execution Engine决定。

  • 加载类的信息存放于一块称为方法区的内存空间。除了类的信息外,方法去中还会存放运行时常量池信息,可能还包括字符串字面量和数字常量(这部分常量信息时Class文件中常量池部分的内存映射)

2.1类加载器ClassLoader角色

  • class file 存在于本地磁盘上

  • clas file 加载到jvm中,称为DNA元数据模板,在方法区

  • 在.class文件->JVM->最终成为元数据模板,此过程就要一个运输工具(类加载器class loader),扮演一个快递员的角色。

2.2 类的加载过程

2.3类加载过程之一:Loading

(1).通过一个类的全限定名获取定义此类的二进制字节流

(2).将这个字节流所能代表的静态存储结果转化为方法区的运行时数据结构

(3).在内存中生成一个代表这个类的java.lang.Class对下并非,作为方法区这个类的各种数据的访问入口

补充:加载.class文件的方式

  • 从本地系统直接加载

  • 通过网络获取,典型场景:web Applet

  • 从zip压缩包中读取,成为日后jar、wa格式的基础

  • 运行时计算生成,使用最多的是:动态代理技术

  • 由其他文件生成,典型场景,JSP应用

  • 从专门数据库提取.class文件,比较少见

  • 从加密文件中获取,典型的防class文件被反编译的保护措施

2.4类加载过程之一:Linking

2.4.1验证(Verfiy)

  • 目的在于确保class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确熊,不会危害虚拟机自身安全

  • 主要包括四种验证,文件格式验证,元数据验证,字节码验证,符合引用验证

2.4.2准备(Prepare)

  • 为类变量分配内存并设置该类变量的默认初始值,即零值

  • 这里不包含final修饰的static,因为final在编译的时候就会分配了,准备阶段会显示初始化

  • 这里不会为实例变量初始化,类变量会分配在方法区中,而实例变量会随着对象一起分配到Java堆中

2.4.3解析(Resolve)

  • 将常量池内的符号引用转换为直接引用的过程 (#1 #2 可以查看字节码文件)

  • 事实上,解析操作往往会伴随着JVM在执行完初始化之后再执行

  • 符号引用就是一组符号来描述锁引用的目标。符号引用的字面形式明确定义在《java虚拟机规范》的class文件格式中。直接引用就是直接指向目标的指针、相对便宜量或一个简洁定位到目标的句柄。

  • 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等。对应常量池中的CONSTANTclassinfo、CONSTANTFiedrefinfo、CONSTANTMethodrefinfo等

2.4类加载过程之一:Initialization

  • 初始化阶段就是执行类构造器方法()过程

  • 此方法不需要定义,是javac编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并而来

  • 构造器方法中指令按语句在源文中出现的顺序执行

  • ()不同于类的构造器。(关联:构造器是虚拟机视角下的())

  • 若该类具有父类,JVM会保证子类()执行前,在父类的()已经执行完毕

  • 虚拟机必须保证一个类的()方法在多线程下被同步加锁

3.类加载器分类

  • JVM支持两种类型的类加载器,分别为引导类加载器(Bootstarp ClassLoader)自定义类加载器(User-Defined ClassLoader)

  • 从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范却没有这么定义,而是将所有派生于抽象类的ClassLoader的类加载器都划分为自定义类加载器

  • 无论类加载器的类型如何划分,在程序中我们最常见的类加载器始终只有3

这里的四者关系是包含关系。不是上层下层,也不是子父类的继承关系

        //获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
//sun.misc.Launcher$AppClassLoader@18b4aac2
System.out.println(systemClassLoader);
//获取其上层:扩展类加载器
ClassLoader extClassLoader = systemClassLoader.getParent();
//sun.misc.Launcher$ExtClassLoader@617c74e5
System.out.println(extClassLoader);
//试图获取上层:获取不到引导类加载器
ClassLoader bootstrapClassLoader = extClassLoader.getParent();
//null
System.out.println(bootstrapClassLoader);
//对于用户自定义类来说:使用系统类加载器进行加载
ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
//sun.misc.Launcher$AppClassLoader@18b4aac2
System.out.println(classLoader);
//String类使用引导类加载器进行加载的
//Java的核心类库都是使用引导类加载器进行加载的
ClassLoader classLoader1 = String.class.getClassLoader();
//null
System.out.println(classLoader1);

3.1虚拟机自带的加载器

3.1.1启动类加载器(引导类加载器,Bootstrap ClassLoader)

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

  • 它用来加载Java的核心库(JAVA_HOME/jre/rt.jar、reources.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类

  • 并不继承自java.lang.ClassLoader,没有父加载器

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

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

3.1.2扩展类加载器(Extension ClassLoader)

  • Java语言编写由sun.misc.Launcher&ExtClassLoader实现

  • 派生于ClassLoader类

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

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

3.1.3应用程序类加载器(系统类加载器,AppClassLoader)

  • java语言编写,由sun.misc..Launcher$AppClassLoader实现

  • 派生于ClassLoader类

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

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

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

  • 通过ClassLoader#getSystemClassLoader()方法获取到该类加载器

        System.out.println("*******启动类加载器********");
URL[] urLs = Launcher.getBootstrapClassPath().getURLs();
for (URL urL : urLs) {
System.out.println(urL.toExternalForm());
}
/**
* *******启动类加载器********
* file:/C:/Program%20Files/Java/jdk1.8.0_152/jre/lib/resources.jar
* file:/C:/Program%20Files/Java/jdk1.8.0_152/jre/lib/rt.jar
* file:/C:/Program%20Files/Java/jdk1.8.0_152/jre/lib/sunrsasign.jar
* file:/C:/Program%20Files/Java/jdk1.8.0_152/jre/lib/jsse.jar
* file:/C:/Program%20Files/Java/jdk1.8.0_152/jre/lib/jce.jar
* file:/C:/Program%20Files/Java/jdk1.8.0_152/jre/lib/charsets.jar
* file:/C:/Program%20Files/Java/jdk1.8.0_152/jre/lib/jfr.jar
* file:/C:/Program%20Files/Java/jdk1.8.0_152/jre/classes
*/
System.out.println("*******扩展类加载器********");
String extsDirs = System.getProperty("java.ext.dirs");
String[] split = extsDirs.split(";");
for (String s : split) {
System.out.println(s);
}
/**
* *******扩展类加载器********
* C:\Program Files\Java\jdk1.8.0_152\jre\lib\ext
* C:\Windows\Sun\Java\lib\ext
*/

3.1.4用户自定义类加载器

  • 在Java的日常应用程序开发中,类的加载器几乎是由3类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,来指定类的加载方式

  • 为什么要自定义类的加载器?

  • 隔离加载类

  • 修改类加载方式

  • 扩展加载源

  • 防止源码泄漏

4.ClassLoader的使用说明

4.1关于ClassLoader

ClassLoader类,它是一个抽象类,其所有的类加载器都集成自ClassLoader(不包含启动类加载器)

方法名称 描述
getParent() 返回类加载器的超类加载器
loadClass(String name) 加载类名称为name的类,返回结果为java.lang.Class类的实例
findClass(String name) 查找名称为name的类,返回结果为java.lang.Class类的实例
findLoadedClass(String name) 查找名称为name的已经被加载过的类,
defineClass(String name,byte[] b,int off,int len) 把字节数组b中的内容转换为一个Java类,返回结果为java.lang.Class类的实例
resolveClasss(Class c) 连接指定的一个Java类

sun.misc..Launcher它是一个java虚拟机的入口应用

4.1获取ClassLoader的路径

5.双亲委派机制

Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,Java虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式。

5.1工作原理

(1).如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行。

(2).如果父类加载器还存在其父类加载器,则进一步向上委托,一次递归,请求最终将到达顶层的启动类加载器

(3).如果父类加载器可以完成类加载任务,就返回成功。倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式。

package java.lang;
/**
* @author Created by niugang on 2020/2/21/12:36
*/
public class String {
static{
System.out.println("自定义String类");
}
}

        java.lang.String str = new java.lang.String();
//没有打印 “自定义String类” 说明用的java核心类库中的String
System.out.println("Hello String");
StringTest stringTest = new StringTest();
//sun.misc.Launcher$AppClassLoader@18b4aac2
System.out.println(stringTest.getClass().getClassLoader());

5.2优势

  • 避免类的重复加载

  • 保护程序安全,防止核心API随意篡改

  • 自定义类:java.lang.String

  • 自定义类:java.lang.StringTest //java.lang.SecurityException: Prohibited package name: java.lang

5.3沙箱安全机制

自定义的String类,但是在加载自定义String类的时候会率先使用引导类加载器加载器,而引导类加载器在加载的过程中会先加载jdk自带的文件(rt.jar包中java\lang\String.class),报错信息说没有mian方法,就是因为加载的是rt.jar包中的String类,这样可以保证对java核心源代码的保护,这样就是沙箱安全机制

6.其他

  • 在JVM中表示两个class对象是否为同一类存在两个必要条件

  • 类的完整类名必须一致,包括包名

  • 加载这个类的ClassLoader(指ClassLoader实例对象),必须相同

  • 换句话说,在JVM中,即时这两个类对象(class对象)来源同一个Class文件,被同有一个虚拟机所加载,但是只要加载他们的ClassLoader实例对象不同,那么两个对象也是不相等的。

6.2对类加载器的引用

JVM必须知道一个类型是由启动类加载器加载的还是由用户类加载器加载的。如果一个类型是由用户类加载器加载的,那么JVM会将这个类加载器的一个引用作为类型信息的一部分保存在方法区中。当解析一个类型到另一个类型的引用的时候,JVM需要保证这两个类型的类加载器是相同的。

微信公众号

JVM第二篇 类加载子系统的更多相关文章

  1. 【JVM第二篇--类加载机制】类加载器与双亲委派模型

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.什么是类加载器 在类加载过程中,加载阶段有一个动作是"通过一个类的全限 ...

  2. 初步了解JVM第二篇

    在一篇<初步了解JVM第一篇>中,我们已经了解了: 类加载器:负责加载*.class文件,将字节码内容加载到内存中.其中类加载器的类型有如下: 启动类加载器(Bootstrap) 扩展类加 ...

  3. JVM上篇:类加载子系统

    JVM类加载 目录 JVM类加载 1.内存结构概述 2.类加载子系统概述 3.类的加载过程 2.1加载 2.2Linking 2.2.1验证(Verify) 2.2.2准备(Prepare) 2.2. ...

  4. JVM 第二篇:垃圾收集器以及算法

    本文内容过于硬核,建议有 Java 相关经验人士阅读. 0. 引言 一说到 JVM ,大多数人第一个想到的可能就是 GC ,今天我们就来聊一聊和 GC 关系最大的垃圾收集器以及垃圾收集算法,希望能通过 ...

  5. 【JVM第一篇--类加载机制】类加载过程

    写在前面的话:本文是在观看尚硅谷JVM教程后,整理的学习笔记.其观看地址如下:尚硅谷2020最新版宋红康JVM教程 一.什么是类加载过程 (1).概述 我们编写的类(.java文件)会被编译器(如ja ...

  6. 【JVM之内存与垃圾回收篇】类加载子系统

    类加载子系统 概述 完整图如下: 如果自己想手写一个 Java 虚拟机的话,主要考虑哪些结构呢? 类加载器 执行引擎 类加载器子系统作用 类加载器子系统负责从文件系统或者网络中加载 Class 文件, ...

  7. JAVA高级篇(二、JVM内存模型、内存管理之第二篇)

    本文转自https://zhuanlan.zhihu.com/p/25713880. JVM的基础概念 JVM的中文名称叫Java虚拟机,它是由软件技术模拟出计算机运行的一个虚拟的计算机. JVM也充 ...

  8. JVM笔记 -- 来,教你类加载子系统

    类加载子系统 类文件首先需要经过类加载子系统,进行加载,进类信息等加载到运行时数据区,生成Klass的实例. 在类加载子系统中有以下3个阶段操作(广义上的加载): 加载阶段 Bootstrap Cla ...

  9. 第二篇 SQL Server代理作业步骤和子系统

    本篇文章是SQL Server代理系列的第二篇,详细内容请参考原文. SQL Server代理作业由一系列的一个或多个作业步骤组成.一个作业步骤分配给一个特定的作业子系统(确定作业步骤去完成的工作). ...

随机推荐

  1. 【WPF学习】第二十六章 Application类——应用程序的生命周期

    在WPF中,应用程序会经历简单的生命周期.在应用程序启动后,将立即创建应用程序对象,在应用程序运行时触发各种应用程序事件,你可以选择监视其中的某些事件.最后,当释放应用程序对象时,应用程序将结束. 一 ...

  2. Linux守护进程之systemd

    介绍 历史上,Linux 的启动一直采用init进程:下面的命令用来启动服务. $ sudo /etc/init.d/apache2 start # 或者 $ service apache2 star ...

  3. Fst指数说明

    群体遗传学--Fst指数,即群体间分化指数,用于群体间分化分析. 群体遗传学中衡量群体间分化程度的指标有很多种,最常用的就是Fst指数.Fst指数,由F统计量演变而来.F统计量(FIS,FIT,FST ...

  4. vim 实用快捷键

    删除当前行:dd 删除上一行:dj 删除下一行:dk 拷贝当前行:yy 交换当前行和其下一行 交换当前字符和其后的一个字符 剪切当前字符:x 剪切当前光标开始向后三个字符:3x 撤销最近一次修改:u ...

  5. 微信小程序框架分析小练手(一)——猫眼电影底部标签导航制作

    旧版猫眼电影底部有4个标签导航:电影.影院.发现.我的,如下图所示: 一.首先,打开微信开发者工具,新建一个项目:movie.如下图: 二.建立如下的一些目录: 三.将底部标签导航图标的素材放到ima ...

  6. C++调用DLL方法

    调用的原理: 调用DLL,首先需要将DLL文件映像到用户进程的地址空间中,然后才能进行函数调用,这个函数和进程内部一般函数的调用方法相同.Windows提供了两种将DLL映像到进程地址空间的方法:隐式 ...

  7. 《Android Studio实战 快速、高效地构建Android应用》--Android Studio操作

    前言 摩尔定律:CPU的处理能力大约18个月翻一倍 Android&Java:想要在Android Studio中开发Android App,必须以充分了解Java为前提(Java流行的原因: ...

  8. Java 接口及接口回调_Chris

    题目: 利用接口和接口回调,实现简单工厂模式,当输入不同的字符,代表相应图形时,利用工厂类获得图形对象,再计算以该图形为底的柱体体积. 代码: 1.Test.java /** * 测试类,包含一个主方 ...

  9. qt creator源码全方面分析(2-6)

    目录 User Interface Text Guidelines 语法和风格 标点 编写工具提示tooltips 编写消息 UI文本大写 使用书本样式大写 使用句子样式大写 准备本地化 标记UI文本 ...

  10. 形象解释各种卷积算法(Convolution animations)

    No padding, no strides Arbitrary padding, no strides Half padding, no strides Full padding, no strid ...