JVM结构 类加载

news2025/1/8 4:33:48

类加载

类加载子系统

在这里插入图片描述

  • 类加载器子系统负责从文件系统或者网络中加载class文件。classLoadr只负责class文件的加载,至于它是否可以运行,则由Exception Engine(执行引擎)决定。
  • 加载类的信息存放于一块成为方法区的内存空间
    在这里插入图片描述
  • class file 存在于硬盘上,可以理解为设计师画在纸上的模板,最终这个模板在执行的时候要加载JVM当中来,根据这个模板实例化出若干个实例。
  • class file 加载到JVM中,被称为DNA元数据模板
  • 此过程需要有一个运输工具(类加载器 ClassLoader),扮演一个快递员的角色。

类加载的过程

在这里插入图片描述

加载

  1. 通过类名(地址)获取此类的二进制字节流。
  2. 将这个字节流所代表的静态存储结构转换为方法区(元空间)的运行时结构。
  3. 在内存中生成一个代表这个类的 java.lang.Class 对象,作为这个类的各种数据访问接口。

链接

验证:对字节码文件格式进行验证,看文件是否被污染,对基本语法格式进行验证
准备: 准备阶段负责对类的静态属性分配内存,并设置默认初始值
不包含使用final修饰的static变量,在编译时进行初始化

public static int val = 123;
//value 在准备阶段值为0,而不是123

静态常量在编译期间就被初始化
解析:将类的二进制中符号引用替换为直接引用
将字节码中的表现形式,转为内存中表现(内存地址)
初始化:类的初始化,为类中定义的静态变量进行赋值

public static int val = 123;
//在初始化阶段后值为123

类什么时候会被加载(初始化)?

  • 在类中运行main方法
  • 通过new关键字创建对象
  • 使用类中的静态变量/方法
  • 反射 Class.forName(“类的地址”)
  • 子类被加载
    以下两种情况类不会被初始化:
static final int b = 20;//编译期间赋值的静态常量

Class[] class = new  Class[10]; // 作为数组类型

类初始化顺序

  • 对static修饰的变量或语句进行赋值
  • 如果包含多个静态变量和静态代码块,则按照自上而下的顺序依次进行。
  • 如果初始化一个类的时候,其父类尚未初始化,则优先初始化父类
  • 顺序是 父类static --> 子类static
public class classInit{
	static {
		num = 20;
	}
	static int num = 10;
	public static void main(String[] args){
		//num从准备到初始化值变化过程 num = 0 --> num = 20 --> num = 10
		System.out.println(num);//10
	}
}

public class classInit{
	static int num = 10;
	static {
		num = 20;
	}
	public static void main(String[] args){
		//num从准备到初始化值变化过程 num = 0 --> num = 10 --> num = 20
		System.out.println(num);//10
	}
}

类加载器分类

  • 站在 JVM 的角度看,类加载器可以分为两种:
  1. 引导类加载器(启动类加载器 Bootstrap ClassLoader).
  2. 其他所有类加载器,这些类加载器由 java 语言实现,独立存在于虚拟机外部,并且全部继承自抽象类 java.lang.ClassLoader.
  • 站在 java 开发人员的角度来看,类加载器就应当划分得更细致一些,自 JDK1.2 以来 java 一直保持者三层类加载器
    在这里插入图片描述
  • 引导类加载器:
    用C/C++语言开发的,JVM底层的开发语言,负责加载java核心类库,与java语言无关。
  • 扩展类加载器
    java语言编写的,由sun.misc.Launcher$ExtClassLoader 实现,继承ClassLoader类,
    从JDK系统安装目录的jre/lib/ext 子目录(扩展目录)下加载类库
  • 应用程序类加载器
    java语言编写的,由sun.misc.Launcher$AppClassLoader实现,派生于ClassLoader类。
    加载程序中自己开发的类
  • 自定义类加载器
public class ClassLoaderDemo{
	public static void main(String[] args){
		ClassLoader classLoader = String.class.getClassLoader();
		  System.out.println(classLoader);//null 因为是由引导类加载的 不是java代码
		 ClassLoader classLoader1 = ClassLoaderDemo.class.getClassLoader();
		 System.out.println(classLoader1);//sun.misc.Launcher$AppClassLoader@184aac2
		  ClassLoader classLoader2 = classLoader1.getParent();
		 System.out.println(classLoader2);//sun.misc.Launcher$ExtClassLoader @1b6d3586
		 System.out.println(classLoader2.getParent());//null classLoader2的父类是由引导类加载器加载的
		 
	}
}

双亲委派机制

  • Java 虚拟机对 class 文件采用的是按需加载的方式,也就是说当需要该类时才会将它的 class 文件加载到内存中生成 class 对象.而且加载某个类的 class 文件时,Java 虚拟机采用的是双亲委派模式,即把请求交由父类处理,它是一种任务委派模式
    在这里插入图片描述
  • 工作原理:
    如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行。
    如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器。
    如果父类加载器可以完成类的加载任务,就成功返回,倘若父类加载器无法完成加载任务,子加载器才会尝试自己去加载,这就是双亲委派机制。
    如果均加载失败,就会抛出 ClassNotFoundException 异常
  • 如果我们自己创建一个java.lang.String类当我们new String()时,仍会加载创建核心类库创建核心类库中的String对象
package java.lang;
public class String{
	static{
		System.out.println("自己的String");
	}
}

new java.lang.String();逐级向上委托,最终引导类加载器找到了系统中真正的String

如何打破双亲委派机制

  • 双亲委派机制是java提供的类加载的规范,但不是强制不能改变的
  • 我们可以通过自定义类的加载器,改变加载方式
    在 ClassLoader 类中涉及类加载的方法有两个,loadClass(String name), findClass(String name),这两个方法并没有被 final 修饰,也就表示其他子类可以重写.
    • 重写 loadClass 方法(是实现双亲委派逻辑的地方,修改他会破坏双亲委派机制, 不推荐)
    • 重写 findClass 方法 (推荐)
      我们可以通过自定义类加载重写方法打破双亲委派机制, 再例如 tomcat 等都有自己定义的类加载

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/196773.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【GPLT 二阶题目集】L2-007 家庭房产

给定每个人的家庭成员和其自己名下的房产,请你统计出每个家庭的人口数、人均房产面积及房产套数。 输入格式: 输入第一行给出一个正整数N(≤1000),随后N行,每行按下列格式给出一个人的房产: 编号…

Java创建线程的七种方法,全网最全面总结~

目录 前言 一、继承Thread,重写run方法 二、实现Runnable接口,重写run方法 三、使用匿名内部类创建 Thread 子类对象 四、使用匿名内部类,实现Runnable接口 五、lambda表达式 六、实现Callable接口 七、使用线程池创建线程 前言 属于基…

末端工具重力辨识

辨识工具重力 法一:6点标定 已知,工件重力在世界坐标系的大小为{0,0,−G}\{0,0,-G\}{0,0,−G},假设工件重心在工具坐标系下的坐标为 {Lx,Ly,Lz}\{L_x,L_y,L_z\}{Lx​,Ly​,Lz​},重力在工件的三个坐标轴分量为 {Gx,Gy,Gz}\{G_x,G_y,G_z\}{G…

Docker安装MySQL8数据库

🎈 作者:互联网-小啊宇 🎈 简介: CSDN 运维领域创作者、阿里云专家博主。目前从事 Kubernetes运维相关工作,擅长Linux系统运维、开源监控软件维护、Kubernetes容器技术、CI/CD持续集成、自动化运维、开源软件部署维护…

为什么要拒绝嵌套代码?

linux 内核的最早作者 linus torvalds 在 linux 内核样式指南 第一节中提到: if you need more than 3 levels of indentation, you’re screwed anyway, and should fix your program. 如果你需要超过3级的缩进,你无论如何都搞砸了,应该修复…

ABBYY15免费照片识别文字识别软件

照片识别文字的软件有哪些?在日常的工作的时候,小伙伴们是不是经常会借助拍摄照片记录一些比较重要的事情或者是一些比较重要的笔记,等回头空闲出来的时候在去整理,那么这时候,如果我们运用好图片识别文字这项技术&…

线性代数篇

主线为花书第二章-线性代数,但其上面一些表述属实费解,于是参考B站3Blue1Brown线性代数和B站同济子豪兄的视频讲解。 先放一句3B1B的话共勉,伙计们不要被数学公式吓到,慢慢钻研,慢慢推肯定能学懂。线性代数这一部分相信…

cannot redeclare block-scoped variable

使用 Vue3.0 的时在模块类中声明方法的时候抛出了如下的异常:cannot redeclare block-scoped variable解决办法检查是否集成了 Vetur 插件,若存在禁用或卸载即可,该插件Vue3.0 的时候会冲突;Vue3.0 集成如下两款即可:名称: TypeScript Vue Plugin (Volar)ID: Vue.vscode-typesc…

Qt 自定义控件 带UI 不带 UI

一般自定义控件原因 有时Qt 现有控件不能满足我们的开发需求,这时候就需要我们进行自定义控件的使用,自定义控件,这大大提高了设计UI的通用性,程序利用,封装; Part1 easy one 继续 Lab 自定义Label控件:文本太长省略…

机械设备管理系统如何帮助企业做好成本核算管理?

随着多元化市场经济的深入发展,机械设备制造企业面临的竞争压力也越来越大,企业要想在激烈的市场环境中生存下去,就得不断提高竞争力。企业提高自身竞争能力最为重要一个途径便是不断提高企业的成本核算及管控能力,降低企业经营成…

java使用导出百万级别数据

用过POI的人都知道,在POI以前的版本中并不支持大数据量的处理,如果数据量过多还会常报OOM错误, 这时候调整JVM的配置参数也不是一个好对策(注:jdk在32位系统中支持的内存不能超过2个G,而在64位中没有限制&a…

栈、堆、全局区/静态存储区、常量区、代码段、到底是什么?

一、程序运行内存分布图 我们知道一个由我们编写好的程序,运行时,我们的程序中写的代码,定义的变量,写的函数、for 循环等等,这些运行时都分布在内存中的哪里吗? 一下是一个程序运行时 内存的各个区域的分…

C语言字符串指针(指向字符串的指针)详解

C语言中没有特定的字符串类型&#xff0c;我们通常是将字符串放在一个字符数组中&#xff0c;这里演示一下&#xff1a;#include<stdio.h> #include<string.h>intmain(){ char str[]"http://csdn.net"; int len strlen(str), i; //直接输出字符串 printf…

一套完全开源,支持多租户,界面配置单点的后端框架JVS,赶紧收藏

今天推荐的这个项目是「JVS数据全家桶中的 JVS微服务框架」—— 是一个免费开源的中后台模版&#xff0c;使用了最新的 vuespring cloud 主流技术开发&#xff0c;开箱即用的中后台前端解决方案&#xff0c;可以直接商用&#xff0c;并且这个脚手架上做了很多商业上的扩展&…

day19 二叉树 | 654、最大二叉树 617、合并二叉树 700、二叉搜索树中的搜索 98、验证二叉搜索树

题目 654、最大二叉树 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出的最大二叉树。右子树是通过数组中最大值右边部分构造出的最大二叉树。 通过给定的数组构…

数据中心转型利润中心:数据如何赋能零售行业营销升级?

通过大数据来提升营销效果已经是零售行业不同业态都绕不过去的话题。以往&#xff0c;市场团队在进行投放时需要依靠营销团队和销售团队的经验来判断&#xff0c;这样的营销策略较为粗放&#xff0c;对用户的感知也不精准&#xff0c;一般都是在海量投放后被动的等待营销反馈。…

C++代码优化(2):条款5~12

"然后自然老去吧&#xff0c;别再依依惜别了"条款5:了解C默默编写并调用了哪些函数(1)小试牛刀地回顾C编译器为类提供的默认函数很多人知道是有6个的。默认构造、拷贝构造、赋值重载、析构函数、重载取地址运算符&#xff0c;但是在C11更新后&#xff0c;又为类对象增…

软件测试项目实战,我们拿到项目第一步应该怎么做【附过程文档】

对于从事软件研发的组织来说&#xff0c;工作类型至少包括项目管理、产品设计、编码、测试、质量保证和软件配置管理&#xff0c;以及其它人员&#xff0c;如文档编制人员和美工人员/系统硬件管理人员等。根据职能需要&#xff0c;可以以半独立方式进行部门和项目的矩阵管理&am…

Let’s Encrypt共建安全的互联网

导读最近关于沃通和 StartCom 这两家 CA 公司的消息让人们再次关注到了网络隐私和安全的问题。随着 Mozilla、苹果和谷歌对这两家 CA 公司处罚落定&#xff0c;很多使用这两家 CA 所签发证书的网站纷纷寻求新的证书签发商。这里面固然有不少可信赖的 CA 公司可以提供服务&#…

UniRx之基本语法格式

前言 想要更好的去学习UniRx&#xff0c;我们最好是先理解UniRx 的语法格式。就像我们去学习英语或者汉语一样&#xff0c;理解了基本的语法规则后&#xff0c;再学其他的就信手拈来了。 语法示例 下面我们来看一个最简单的示例&#xff0c; Observable.EveryUpdate().Where…