首页 > 其他分享 >JVM类的加载和加载器

JVM类的加载和加载器

时间:2023-07-18 17:55:26浏览次数:26  
标签:java 自定义 classLoader JVM 方法 class 加载

JVM类的加载和类的加载器

一.类的加载过程

类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。

1.加载

一般来说加载分为以下几步:
(1) 通过一个类的全限定名获取此类的二进制字节流
(2) 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
(3) 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

加载.class文件的方式

  • 从本地系统中直接加载

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

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

  • 运行时计算生成,使用最多的是:动态代理技术由其他文件生成,典型场景: JSP应用

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

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

2.链接

2.1验证(Verify)

  • 目的在于确保class文件的字节流中包含信息符合当前虚拟机要求,保证被加载类的正确性,不会危害虚拟机自身安全。
  • 主要包括四种验证,文件格式验证,元数据验证,字节码验证,符号引用验证

2.2准备(Prepare)

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

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

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

2.3解折(Resolve)

  • 将常量池内的符号引用转换为直接引用的过程。

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

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

  • 解析动作主要针对类或接口、字段、类方法、接口方法、方法类型等。对应常量池中的CONSTANT class info、CONSTANT Fieldref info、CONSTANT Methodref info等

3.初始化

  • 初始化阶段就是执行类构造器方法clinit的过程。

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

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

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

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

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

二.类的加载器

4.作用

  • 类加载器子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识。

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

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

5.分类

  • JVM支持两种类型的类加载器,分别为引导类加载器 (BootstrapclassLoader)和自定义类加载器[user-Defined ClassLoader)
  • 从概念上来讲,自定义类加载器一般指的是程序中由开发人员自定义的一类类加载器,但是Java虚拟机规范却没有这么定义,而是将所有派生于抽象classLoader的类加载器都划分为自定义类加载器。
  • 无论类加载器的类型如何划分,在程序中我们最常见的类加载器始终只有3个,如下所示:

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

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

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

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

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

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

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

5.2扩展类加载器(Extension ClassLoader)

  • Java语言编写,由sun.misc.LauncherSExtClassLoader实现
  • 派生于classLoader类
  • 父类加载器为启动类加载器
  • 从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的ire/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。

5.3应用程序类加载器(系统类加载,AppclassLoader)

  • java语言编写,由sun.misc.LauncherSAppClassLoader实现

  • 派生于classLoader类

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

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

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

  • 通过classLoader.getSystemClassLoader0)方法可以获取到该类加载器

5.4用户自定义类加载器

在Java的日常应用程序开发中,类的加载几乎是由上述3种类加载器相互配合执行的,在必要时,我们还可以自定义类加载器,来定制类的加载方
为什么要自定义类加载器?

  • 隔离加载类
  • 修改类加载的方式
  • 扩展加载源
  • 防止源码泄漏

用户自定义类加载器实现步骤:

1.开发人员可以通过继承抽象类java.lang.classLoader类的方式,实现自己的类加载器,以满足一些特殊的需求

2.在JDK1.2之前,在自定义类加载器时,总会去继承classLoader类并重写loadclass0)方法,从而实现自定义的类加载类,但是在JDK1.2之后已不再建议用户去覆盖loadclass()方法,而是建议把自定义的类加载逻辑写在findclass()方法中

3.在编写自定义类加载器时,如果没有太过于复杂的需求,可以直接继承URIClassLoader类,这样就可以避免自己去编写findclass()方法及其获取字节码流的方式,使自定义类加载器编写更加简洁。

classLoader类,它是一个抽象类,其后所有的类加载器都继承自classLoader (不包括启动类加载器)

获取ClassLoader的途径

标签:java,自定义,classLoader,JVM,方法,class,加载
From: https://www.cnblogs.com/dupengpeng/p/17563662.html

相关文章

  • python加载多光谱照片
    Python加载多光谱照片在现实生活中,我们经常使用彩色照片来记录和分享我们的回忆。然而,有时候我们需要更多的信息来了解照片中的物体和场景。这就需要使用到多光谱照片,它们可以提供不同波长范围的图像信息。多光谱照片通常由一些特殊的相机或传感器捕获,这些设备能够同时记录不同波......
  • python加载npz
    Python加载npz文件在Python中,我们经常需要加载和保存数据。而NumPy是Python中一个非常常用的科学计算库,其中提供了一个功能强大的数据存储格式——npz。npz是NumPy自定义的压缩格式,它可以用于存储多个数组,并且可以通过键值对的方式访问数组。这使得npz成为在科学计算和机器学习中......
  • 类加载的过程是什么?
    转载:https://www.bilibili.com/video/BV1RV4y117an/?spm_id_from=333.337.search-card.all.click&vd_source=46d50b5d646b50dcb2a208d3946b1598......
  • django查询-列延迟加载only()、defer()
    这玩意和sqlalchemy的几乎一样。only():只加载给定的列,其他列只有在使用时会发起二次查询defer():不加载指定的列,刚好和only()相反。实例:>>>ret=BookInfo.objects.get(id=1).only("name")#1、先导入connection,获取django查询的所有sql语句>>>fromdjango.dbimportconn......
  • ios 加载网络图片
    iOS加载网络图片在iOS开发中,我们经常需要从网络上加载图片并显示到用户界面上。本文将介绍一种简单的方法来加载网络图片,并附带代码示例。使用第三方库SDWebImageSDWebImage是一个广泛使用的第三方库,它提供了一种简单而高效的方式来加载网络图片,并支持图片缓存和缓存管理。......
  • jvm中引用的类型和强引用、软引用、弱引用,虚引用
    转载:https://www.bilibili.com/video/BV1ST411J7Bk/?spm_id_from=333.337.search-card.all.click&vd_source=46d50b5d646b50dcb2a208d3946b1598......
  • class文件的加载过程
    1、在加载class文件的时候,JVM会先加载类中的所有静态成员(方法,变量,静态代码块)都加载到方法区class文件的所处静态区中2、当把所有的静态成员加载完成之后,开始给类中的所有静态成员变量进行默认初始化3、当类中的所有静态成员变量默认初始化之后,接着开始给所有静态成员变量显示赋......
  • selenium滚动加载数据解决方案
    有些网站时一直滚动就会加载新数据的,在selenium中解决方法:defloaddata_by_scroll(self,driver):js='returndocument.body.scrollHeight;'#获取当前高度check_height=driver.execute_script(js)whileTrue:#先滚动到最底部,如果能继续加载更......
  • 【后端面经-Java】JVM内存分区详解
    @目录1.JVM内存分区简介2.JVM栈3.JVM堆4.JVM方法区5.JVM内存分配实例面试模拟参考资料1.JVM内存分区简介JVM内存分区如图所示:主要有如下几个区域:栈(Stack)堆(Heap)方法区(MethodArea)程序计数器(PC)本地方法栈(NativeMethodStack)其中,程序计数器用于存储线程当前执行的......
  • JVM专栏-内存分配与回收策略
    对象的内存分配,就是在堆上分配(也可能经过JIT编译后被拆散为标量类型并间接在栈上分配),对象主要分配在新生代的Eden区上,少数情况下可能直接分配在老年代,分配规则不固定,取决于当前使用的垃圾收集器组合以及相关的参数配置。以下列举几条最普遍的内存分配规则,供大家学习。对象优......