p7付费课程笔记:jvm基础知识、字节码、类加载器

这篇具有很好参考价值的文章主要介绍了p7付费课程笔记:jvm基础知识、字节码、类加载器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.编程语言

演化

机器语言->编程语言->高级语言(java,c++,Go,Rust等)

面向过程–面向对象-面向函数

java是一种面向对象、静态类型、编译执行,有VM(虚拟机)/GC和运行时、跨平台的高级语言。重点:VM(虚拟机)/GC(Garbage Collector)和运行时、跨平台。
p7付费课程笔记:jvm基础知识、字节码、类加载器

跨平台步骤:字节码文件被虚拟机加载(类加载器)加载到内存中,转换成具体的对象
p7付费课程笔记:jvm基础知识、字节码、类加载器

2.字节码

结构

Java byteCode由单字节(byte)指令构成,理论上最多支持256个操作码(opcode)。实际上java只使用了200左右的操作码,其他留给了调试操作。

根据指令的性质大概分为四大类:

1.栈操作指令,包括与局部变量交互的指令,

2.程序流程指令,

3.对象操作指令,比如方法调用的指令,

4.算数运算以及类型转换的指令,

运行步骤:
p7付费课程笔记:jvm基础知识、字节码、类加载器

JVM是一个基于栈的计算机,每个线程都有独属于自己的线程栈(JVM Stack),用语存储栈帧。每次调用方法就会自动创建一个线程栈。栈帧是由操作数栈、局部变量表以及一个class引用组成,class引用中又包含着我们使用的常量池

操作demo:https://juejin.cn/post/7141206840456511496/

3.类加载器

类生命周期的七个步骤

p7付费课程笔记:jvm基础知识、字节码、类加载器

前五步是我们通常所说的类加载过程,其中2、3、4可以合在一起称为-链接:

1 找到class文件,读出来
2 验证格式,解析字段方法,所有符号转化为实际引用
3 类相关初始化

1.加载(Loading):加载阶段是通过类加载器(ClassLoader)将类的字节码文件加载到JVM内存中。JVM通过类加载器找到类的二进制数据流,这个数据流是从硬盘上读取的。
2.验证(Verification):在类加载后,JVM会对类的二进制数据流进行验证。这个阶段是为了确定类的二进制数据的正确性,包括类的语法是否正确等。
3.准备(Preparation):在验证后,JVM为类的静态变量分配内存空间,并将其赋予默认值。例如对于boolean型变量,它的默认值是false;对于char型变量,它的默认值是0;对于int型变量,它的默认值是0等。
4.解析(Resolution):这个阶段将类中的符号引用转换为直接引用。主要是针对类或接口、字段、类方法、接口方法、方法类型、方法句柄和调用点限定符类符号引用进行。简单来说,符号引用就是指类、方法、字段的名称,而直接引用就是指具体的内存地址。
5.初始化(Initialization):初始化阶段是类加载过程的最后一步。在这个阶段,JVM会执行类构造器方法 (static{}块) ,并且初始化静态变量。如果静态变量没有被显式初始化,那么它会被初始化为默认值。同时,如果该类还有父类的话,JVM会先初始化父类。
6.使用(Using):一旦类被加载并初始化后,就可以被使用和创建对象了。
7.卸载(Unloading):当类的Class对象不再被引用时,Class对象就结束了生命周期,类在方法区中的数据也会被卸载,从而结束类的生命周期。

类的加载时机

虚拟机规范中并没有强制约束何时进行加载,但是规范严格规定了有且只有下列五种情况必须对类进行初始化(加载、验证、准备都会随着发生):

1.3.1 遇到 new、getstatic、putstatic、invokestatic 这四条字节码指令时,如果类没有进行过初始化,则必须先触发其初始化。最常见的生成这 4 条指令的场景是:使用 new 关键字实例化对象的时候;读取或设置一个类的静态字段(被 final 修饰、已在编译器把结果放入常量池的静态字段除外)的时候;以及调用一个类的静态方法的时候。

1.3.2 使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行初始化,则需要先触发其初始化。

1.3.3当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

1.3.4 当虚拟机启动时,用户需要指定一个要执行的主类(包含 main() 方法的那个类),虚拟机会先初始化这个主类;

1.3.5 当使用 JDK.7 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果为 REF_getStatic, REF_putStatic, REF_invokeStatic 的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化;

以上 5 种场景中的行为称为对一个类进行主动引用。除此之外,所有引用类的方式都不会触发初始化,称为被动引用。被动引用的常见例子包括:

通过子类引用父类的静态字段,不会导致子类初始化。

通过数组定义来引用类,不会触发此类的初始化。该过程会对数组类进行初始化,数组类是一个由虚拟机自动生成的、直接继承自 Object 的子类,其中包含了数组的属性和方法。

常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。

总结:显式,隐式隐式,子类父类,实现类和接口,反射,动态调用显式,main方法,new,静态字段和方法

4.类加载器和特点

p7付费课程笔记:jvm基础知识、字节码、类加载器

1.启动类加载器(BootstrapClass Loader)

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

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

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

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

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

启动类加载器不像其他类加载器有实体,它是没有实体的,JVM将C++处理类加载的一套逻辑定义为启动类加载器。因此,启动类加载器是无法被Java程序调用的。

2.扩展类加载器(Extension Class Loader)

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

派生于ClassLoader类

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

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

public static void main(String[] args) {
    ClassLoader classLoader = ClassLoader.getSystemClassLoader().getParent();

    URLClassLoader urlClassLoader = (URLClassLoader) classLoader;

    URL[] urls = urlClassLoader.getURLs();
    for (URL url : urls) {
        System.out.println(url);
    }
}

3.应用程序加载器(系统类加载器,System Class Loader/App Class Loader)

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

派生于ClassLoader类

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

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

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

通过ClassLoader#getSystemClassLoader()方法可以获得到该类加载器

public static void main(String[] args) {
    String[] urls = System.getProperty("java.class.path").split(":");

    for (String url : urls) {
        System.out.println(url);
    }

    System.out.println("================================");

    URLClassLoader classLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();

    URL[] urls1 = classLoader.getURLs();
    for (URL url : urls1) {
        System.out.println(url);
    }
}

4.用户自定义类加载器

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

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

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

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

p7付费课程笔记:jvm基础知识、字节码、类加载器

双亲委派(重点)

双亲委派机制的原理:

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

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

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

优点:

避免类的重复加载,确保一个类的全局唯一性

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

缺点:

无法做到不委派,无法做到向下委派

在某些场景下双亲委派制过于局限,所以有时候必须打破双亲委派机制来达到目的。例如:SPI机制,这个SPI机制涉及到打破双亲委派机制,工作中没有涉及到就不细说了,感兴趣的同学可以自己研究下。

双亲委派在JVM中的实现代码:

protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        // 首先,去检查类是否已经被加载
        Class<?> c = findLoadedClass(name);
        // 如果类还未被加载
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                // 获取父类加载器加载该类
                if (parent != null) {
                    // this 是AppClassLoader, this.parent是ExtClassLoader
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        // 判断类是否被解析
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

这一期的课程大概就讲了这么多吧,说实话看完还是好多记不住和不理解,也是反复记忆并且查了好多资料才知道,所以不理解很正常,没有接触过就能一遍看懂的一般都是高级及以上了,慢慢看就可以了。看一点就是进步。

下期这明天写,大概是内存模型和JMM的相关知识,小伙伴可以先复习下,然后查漏补缺。

视频

第一次录没录好,有啥不好的可以在评论区告诉我。因为百度云上传视频需要用会员,所以使用了阿里云。没有条件的小伙伴可以私信我,单发。
阿里云盘视频链接:https://www.aliyundrive.com/s/LqvyyqsDgyS

今天就到这里吧,感觉有用的小伙伴可以点个赞,你的支持就是我更新的最大动力!文章来源地址https://www.toymoban.com/news/detail-497343.html

到了这里,关于p7付费课程笔记:jvm基础知识、字节码、类加载器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《JavaEE初阶》JVM基础知识

    本章主要介绍JVM中比较重要的三个内容: JVM内存区域划分 JVM类加载机制 JVM垃圾回收机制 当我们创建一个java进程时,启动时会向操作系统申请一块内存,JVM会将这块内存划分为几个区域: 堆 栈 程序计数器 方法区 堆: 堆上主要存放的是new的对象,是最重要的区域,也是内存划分最多

    2024年02月09日
    浏览(38)
  • JVM-环境准备&性能指标&基础知识

    环境准备性能指标基础知识 环境准备 JDK — 工具 JDK(Java Development Kit) 是用于开发 Java 应用程序的软件开发工具集合,包括了 Java 运行时的环境(JRE)、解释器(Java)、编译器(javac)、Java 归档(jar)、文档生成器(Javadoc)等工具。简单的说我们要开发 Java 程序,就需要

    2024年02月07日
    浏览(58)
  • JVM,关于JVM基础的知识,你确定不了解一下吗?

    目录 一.JVM的概念 什么是JVM? 二.JVM的运行流程 1.class文件如何被JVM加载并运行 2.JVM运行时数据包括哪些区域(M) 三.类加载的过程(M) 四.双亲委派模型 1.双亲委派模型分析 2.JAVA中有哪些类加载器(M) 五.垃圾回收机制 1.死亡对象的标识 ①引用计数算法 ②可达性分析算法

    2024年02月02日
    浏览(43)
  • Java基础常考知识点(基础、集合、异常、JVM)

    作者: 逍遥Sean 简介:一个主修Java的Web网站游戏服务器后端开发者 主页:https://blog.csdn.net/Ureliable 觉得博主文章不错的话,可以三连支持一下~ 如有需要我的支持,请私信或评论留言! 本文收集Java核心的面试常考知识点,码起面试之前复习!!! JDK(Java SE Development Kit) ,

    2024年02月07日
    浏览(57)
  • jvm中类和对象定义存储基础知识

    Class文件结构主要有两种数据结构: 无符号数和表 • 无符号数 :用来表述数字,索引引用、数量值以及字符串等,比如 图1中类型为u1,u2,u4,u8分别代表1个字节,2个字节,4个字节,8个字节的无符号数 • 表 :表是有由多个无符号数以及其它的表组成的复合结构,比如图1中类

    2024年02月08日
    浏览(54)
  • JAVA后端开发面试基础知识(一)——JVM

    Class loader(类装载) 根据给定的全限定名类名(如: java.lang.Object)来装载class文件到 Runtime data area中的method area。 Execution engine(执行引擎) 执行classes中的指令。 Native Interface(本地接口) 与native libraries交互,是其它编程语言交互的接口。 Runtime data area(运行时数据区域) 这就是我们常说

    2024年03月10日
    浏览(61)
  • Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)

    Java 是一种广泛使用的面向对象编程语言,在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性,适用于多种应用场景,包括企业应用、移动应用、嵌入式系统等。          以下是几个面试技巧:    1. 复习核心概念: 回顾 Java 的核心概念,如面向对象编

    2024年01月18日
    浏览(57)
  • JVM基础知识(内存区域划分,类加载,GC垃圾回收)

    目录 内存区域划分 JVM中的栈 JVM中的堆 程序计数器 方法区(元数据区) 给一段代码,某个变量在哪个区域上? 类加载 类加载时机 双亲委派模型 GC 垃圾回收机制 GC 实际工作过程 1.找到垃圾/判定垃圾 1.可达性分析(Java中的做法) 2.引用计数 2.清理垃圾 1.标记清除 2.复制算法 3.标记整

    2024年02月07日
    浏览(65)
  • 云计算第1阶段_Linxu基础知识_day03,字节跳动8年老Linux运维面试官经验谈

    5 远程连接sshd服务 ps:sshd默认端口号:22 5.1 手动修改默认端口号 6 文件拷贝、移动、删除 6.1 拷贝文件或目录 6.2 移动文件或目录 **ps:**判断上一条命令是否执行成功 命令:echo $? 如果返回值为0,证明我们上一条命令执行是成功的, 如果返回值非0,证明我们上一条命令执行

    2024年04月12日
    浏览(43)
  • stm32串口自定义协议接收一串十六进制数据(将其中两个字节转化为十进制数据)+部分串口基础知识

    位(bit): 二进制数中的一个数位,可以是0或者1,是计算机中数据的最小单位。 字节(Byte): 计算机中数据的基本单位,每8位组成一个字节。各种信息在计算机中存储、处理至少需要一个字节。 例如,一个ASCII码用一个字节表示,一个汉字用两个字节表示。 字(Word):

    2023年04月08日
    浏览(64)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包