初涉JVM

news2024/11/18 14:31:51

JVM

字节码、类的生命周期、内存区域、垃圾回收

  • JVM主要功能:

    • 解释运行(翻译字节码
    • 内存管理(GC
    • 即使编译(Just - In - Time, JIT
      • 短时间内常使用到的字节码翻译成机器码存储在内存中,达到减少解释的次数,性能提升,空间换时间
      • 在这里插入图片描述
  • JVM的组成:

    • 字节码文件

      • 组成;

      • 在这里插入图片描述

      • 基本信息:

        • 文件不是通过文件拓展名来确定文件类型的
        • 软件是通过文件的头几个字节去校验文件的类型
        • Java字节码文件中,将文件头称为magic魔数(CAFEBABE)
        • 主副版本号指的是编译字节码文件的JDK版本号
        • 版本号的作用就是判断当前字节码的版本和运行的JDK是否兼容
        • 主版本号 — 44 就是JDK的数字
        • 版本不兼容的解决方案:
        • 升级JDK(容易引发其他问题,需要大量测试)
        • 更换依赖的版本号,以满足JDK的要求(建议采用)
      • 常量池:

      • 作用:避免相同的内容重复定义,节省空间

      • 方法:

        • 操作数栈是临时存放数据的地方
        • 局部变量表是存放方法中的局部变量的位置

在这里插入图片描述
在这里插入图片描述

  • 类的生命周期:

    • 加载 --> 连接(验证–>准备–>解析)–>初始化–>使用–>卸载

    • 加载

      • 类加载器根据类的全限定名通过不同的渠道以二进制流的方式获取字节码信息。

      • 程序员可以使用java代码拓展的不同的渠道:

        1. 本地文件:磁盘上的字节码文件
        2. 动态代理技术:查询运行时使用动态代理生成
        3. 通过网络传输的类:早期Applet技术使用
      • 类加载器在加载完类之后,JVM会将字节码中的信息保存到内存的方法区中,生成一个InstanceKlass,保存类的所有信息

        • 这个InstanceKlass是用CPP编写的,不能用Java操作
      • 同时,JVM还会在堆中生成一份与方法去中数据类似的java.lang.Class对象

        • 这个堆中对象的信息是少于InstanceKlass的,只有需要用到的信息

        • 作用是在Java代码中去获取类的信息以及存储静态字段的数据

      • 方法区和堆中的这两个对象是通过引用相互关联的

      • 对于开发者来说,只需要访问堆中的对象,而不是InstanceKlass,这样JVM就能很好地控制开发者访问数据的范围

    • 连接(验证–>准备–>解析)

      • 验证: 验证内容是否满足《Java虚拟机规范》
      • 准备:给静态变量赋初值(默认值)
        • 如果是final修饰就会这一步直接初始化
      • 解析:将常量池中的符号引用替换成指向** **
        • 符号引用就是字节码文件中使用编号来访问常量池中的内容
    • 初始化:

      • 执行静态代码块中的代码,为静态变量赋值
      • 执行字节码文件中clinit部分的字节码指令
      • 以下四种方式会导致类的初始化:
        1. 访问一个类的静态变量或静态方法,如果是final修饰过的且等号右边是常量,就不会触发初始化
        2. 调用Class.forName(String clsaaName)
        3. new一个该类的对象
          • 构造代码块{ }优于构造方法先执行
        4. 执行Main方法的当前类
      • clinit指令在特定情况下不会触发:
        1. 无静态代码块且无静态变量赋值语句
        2. 有静态变量声明,无静态变量赋值语句
        3. 静态变量用final修饰
      • 还有一点:
        1. 直接访问父类的静态变量,不会触发子类的初始化
        2. 子类的初始化clinit调用之前,会先调用父类的clinit初始化方法
    • 卸载(在GC中讲到)

  • 类加载器(ClassLoader):

    • classloader是JVM提供给应用程序去实现获取类和接口字节码数据的技术

    • 类加载器的分类:(JDK8及以前)

      • 分为两类,一类是java实现,一类是JVM底层源码实现

      • JVM底层CPP实现

        • Bootstrap启动类加载器:加载java中最核心的类
      • Java实现的

        在这里插入图片描述

        • Extension扩展类加载器:允许扩展Java中比较通用的类
        • Application应用程序加载器:加载应用使用的类
    • 双亲委派机制:

      • 作用

        1. 保证类加载的安全性:避免恶意代码替换掉JDK核心类
        2. 避免重复加载
      • 双亲委派机制指的是:

        • 当一个类加载器收到加载类的任务时,会自底向上查找是否加载过,再由顶向下进行加载(看是否在自己的加载路径中)
        • 在这里插入图片描述
      • 如何去主动加载一个类:

        1. 使用Class.forName方法,使用当前类的类加载器去加载指定的类

          ClassLoader classLoader = Demo1.class.getClassLoader();
          
        2. 获取到类加载器,通过类加载器的loadClass方法指定某个类加载器加载

          Class<?> clazz = classLoader.loadClass("com.xxx.xxx");
          
    • 打破双亲委派机制:

      1. 自定义类加载器

        • 关键就是重写loadClass的findclass方法,将双亲委派机制的代码去除
        • Tomcat就是通过这种方式实现应用之间的类隔离
      2. 线程上下文类加载器

        • JDBC的例子:

          在这里插入图片描述

        • SPI就是使用的线程上下文中保存的类加载器进行类的加载,这个类一般是应用程序类加载器

          ClassLoader cl = Thread.currentThread().getContextClassLoader();
          
        • 这种由启动类加载器加载的类,委派应用程序类加载器去加载类的方式,打破了双亲委派机制

        • 当然JDBC这个案例有不同的看法:

          1. 从SPI角度是打破了双亲委派机制的
          2. 如果从类加载器的角度去看,又是符合双亲委派机制的
      3. OSGi模块化

    • JDK8之后的类加载器:

      • 启动类加载器使用java编写,继承自BuiltinClassLoader实现从模块中找到要加载的字节码资源文件
      • 扩展类加载器被替换成平台类加载器,继承自BuiltinClassLoader
  • 运行时数据区:

    • 定义:JVM在运行java程序过程中管理的内存区域

    • 分类:

      在这里插入图片描述

      1. JVM栈

        • JVM栈存的是java方法,每一个方法的调用使用一个栈帧来保存

        • JVM栈存的栈帧多了是会内存溢出的

        • 栈帧的组成:

          • 局部变量表
            • 保存的内容有:实例方法的this对象,方法的参数,局部变量
            • 栈帧的局部变量表是一个数组,数组中每一个位置称之为槽(slot),浮点数类型占用两个slot,其他类型占用一个slot
            • 为了节省空间,表中的slot是可以复用的,一旦某个局部变量不再生效,当前槽可以复用
          • 操作数栈
            • 执行指令的过程中,用来存放临时数据的一块区域
            • 编译器就确定了栈的最大深度
          • 帧数据
            • 保存了直接引用到内存引用的映射关系(动态链接
            • 保存了方法出口
            • 保存了异常表
      2. 本地方法栈

        • 本地方法栈存的是native本地方法的栈帧
        • 在Hotspot虚拟机中,JVM栈和本地方法栈实现上使用了同一个栈空间
      • 一般程序堆内存是看见最大的一块内存区域。

      • 创建的对象都存在堆上

      • 对象放多了也会内存溢出

      • 堆空间有三个需要的值:

        在这里插入图片描述

        1. used:当前已使用的堆内存
        2. total:JVM已经分配的可用堆内存
        3. max:JVM可以分配的最大堆内存
    • 方法区

      • JDK7及之前,方法区是放在堆里面的永久代空间
      • JDK8及之后,方法区放在元空间中,元空间位于OS维护的直接内存中
      • 方法区存放了三部分内容:
        1. 类的元信息:类的基本信息(InstanceKlass对象)
        2. 运行时常量池:字节码文件中的常量池内容
        3. 字符串常量池(放在堆里面):字符串常量
  • 直接内存;

    • 并不属于java运行时的内存区域
    • 引入了NIO机制,直接使用直接内存
    • 主要解决了以下两个问题:
      1. java堆中的对象如果还不再使用要回收,回收时会影响对象的创建和使用
      2. IO操作比如读文件,要先把文件读入内存再把数据复制到堆中。现在直接放入直接内存,同时堆上维护直接内存的引用,减少数据复制的开销
  • GC:

    • PC,JVM栈,本地方法栈这三个是线程不共享的部分,都是伴随着线程的创建而创建,线程的销毁而销毁。而方法的栈帧在执行完方法后就会弹出栈并释放掉对应内存

    • 方法区的回收:

      • 方法区主要就是回收不再使用的
      • 判定一个类是否可以被回收的三个条件:
        1. 该类的所有实例对象都被回收,在堆中没有其实例对象及子类对象
        2. 加载该类的类加载器已经被回收
        3. 该类的java.lang.Class对象没有在任何地方被引用
      • 手动触发回收:System.gc();
    • 堆回收:

      • java对象的是否能被回收,是根据对象是否被引用来决定的

      • 常见的判断方法:

        1. 引用计数法
          • 引用计数法为每个对象维护一个引用计数器,初始值为0,当对象被引用时加1,取消引用减1
          • 优点是实现简单
          • 缺点:
            1. 加一减一都需要维护计数器,对系统系统有一定影响
            2. 存在循环引用问题,对象无法回收
        2. 可达性分析算法
          • 可达性分析将对象分为两类:垃圾回收的根对象和普通对象,对象之间存在引用关系
          • GC Root 对象:
            • 线程Thread 对象
            • 系统类加载器加载的java.lang.Class对象
            • 监视器对象,用来保存同步锁synmchornized关键字持有的对象
            • 本地方法调用使用的全局对象
      • 五种对象引用

        1. 强引用 :可达性算法中描述的对象引用就是强引用

        2. 软引用:

          • 如果一个对象只有软引用关联到它,当程序内存不足时,就会将软引用中的数据进行回收

          • 软引用常用于缓存中

          • SoftReference类实现软引用

          • 把对象包装进软引用对象中:

            new SoftReference<对象类型> (对象)
            
        3. 弱引用:

          • 机制与软引用相似,区别是,GC的时候,不管内存够不够都会直接被回收
          • WeakReference类实现弱引用
          • 弱引用主要在ThreadLocal中使用
        4. 虚引用:

        5. 终结器引用:

      • GC算法

        • GC的过程会通过单独的GC线程来完成,不管是用哪种GC算法,都会有部分阶段需要停止所有用户线程,这被称为STW(stop the world)

        • 判断GC算法优秀的三个指标:

          1. 吞吐量
            • 执行用户代码的时间/(执行用户代码的时间 + GC时间)越大越好
          2. 最大暂停时间
            • STW时间的最大值
          3. 堆使用效率
        • 三个指标不可兼得,一般来说:

          堆内存越大,最大暂停时间越长。想要减少最大暂停时间,就会降低吞吐量

        • 不同的GC算法适用不同的场景

        • 标记 - 清除算法 —> 复制算法 —> 标记 - 整理算法 —> 分代GC

        • 分代GC

          • 结合了前几种算法

          • 在这里插入图片描述

          • 分代回收时,创建出的对象,首先会被放在Eden区

          • Eden区装满后,就会触发年轻代的GC,称为Young GC 或 Minor GC

          • Minor GC 会把Eden区和From区中需要回收的对象回收,把没有回收的对象放进to区

          • 然后S0变成to区,S1变成from区

          • 每次Eden区装满后,就会触发 Minor GC,对象的年龄会+1

          • 对象的年龄达到阈值(max = 15)会被晋升到老年代

          • 当老年代空间不足时,就会触发Full GC,对整个堆进行GC

        • 垃圾回收器

          • 垃圾回收器是GC算法的具体实现

          • 由于垃圾回收器也是分为年轻代和老年代,除G1外其他的垃圾回收器必须成对组合进行使用

          • 在这里插入图片描述

          • JDK9后默认的垃圾回收器是G1 垃圾回收器

          • Parallel Scavenge 关注吞吐量,允许用户设置最大暂停时间,但是会减少年轻代可用空间的大小

          • CMS关注暂停时间,但是吞吐量方面会下降

          • G1 垃圾回收器的设计目标就是将上面两种垃圾回收器的优点融合:

            1. 支持巨大的堆空间回收,并有较高的吞吐量’
            2. 支持CPU并行垃圾回收
            3. 允许用户设置最大暂停时间
          • G1的整个堆被划分为多个大小相等的区域,区域不要求是连续的,区的大小是堆空间大小/2048

            在这里插入图片描述

          • G1的GC方式有两种:

            1. Young GC
            2. Mixed GC
          • GC流程:

            1. 先创建的对象放在Eden区。
            2. 当G1判断年轻代区不足(max默认60%),无法分配对象时会执行Young GC
            3. 标记出Eden和Survivor区中的存活对象
            4. 根据配置的最大暂停时间选择某些区将存活对象复制到一个新的Survivor区中(年龄+1),清空这些区
            5. 当某个对象的年龄达到阈值(默认15),会被放到老年代
            6. 部分对象如果大小超过区的一半,会被直接放到老年代,这类老年代被称为Humongous区
            7. 对象的总堆占有率达到阈值(默认45%),会触发Mixed GC。回收部分老年代和全部年轻代以及大对象区。采用复制算法完成
            8. G1对老年代的清理会选择存货度最低的区域来进行回收,这样就可以保证回收效率最高,就是G1(Garbage first)名字的由来
            9. 最后的清理阶段使用复制算法,不会产生内存碎片
            10. 如果清理过程中发现没有足够的空区存放转移的对象,会出现Full GC
              Survivor区中(年龄+1),清空这些区
            11. 当某个对象的年龄达到阈值(默认15),会被放到老年代
            12. 部分对象如果大小超过区的一半,会被直接放到老年代,这类老年代被称为Humongous区
            13. 对象的总堆占有率达到阈值(默认45%),会触发Mixed GC。回收部分老年代和全部年轻代以及大对象区。采用复制算法完成
            14. G1对老年代的清理会选择存货度最低的区域来进行回收,这样就可以保证回收效率最高,就是G1(Garbage first)名字的由来
            15. 最后的清理阶段使用复制算法,不会产生内存碎片
            16. 如果清理过程中发现没有足够的空区存放转移的对象,会出现Full GC

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

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

相关文章

whaler_通过镜像导出dockerfile

1、Whaler简介 Whaler:从镜像导出Dockerfile&#xff0c;whaler英文释义捕鲸船。 2、下载安装 # wget -cO /usr/local/bin/whaler https://github.com/P3GLEG/Whaler/releases/download/1.0/Whaler_linux_amd64 3、赋予可执行权限 [rootlocalhost ~]# chmod x /usr/local/…

Android OTA刷机包制作学习笔记

前言 OTA是一个再常见不过的需求&#xff0c;Android提供了recovery用于完成相关操作。 常规OTA包制作有两种&#xff1a; 有项目的完整AOSP源码&#xff0c;可以在成构建产物zip包后利用官方脚本制作。具体参阅&#xff1a;Office OTA假设你没有1的条件那么可以利用官方非A/…

exo-tinggrad 架构解析

目录 exo-tinggrad 架构解析 8B 模型配置 70B 模型配置 exo-tinggrad 架构解析 这个项目目录包含了一系列与Python相关的文件和文件夹,它们共同构成了一个可能的项目或库。这些文件和文件夹按照特定的命名和组织方式被放置在了一起,以便于管理、开发和维护。 tinygrad: 这…

24.7.28(tarjan 割点,割边,多重背包单调队列优化)

星期一&#xff1a; cf round 960 div2 B 简单构造 cf传送门 题意有点绕 思路&#xff1a;开始容易想到 y前和 x后全-1&#xff0c;y到x填1的构造&#xff0c;但对于 5 2 1&#xff0c;1 1 -1 -1 -1有问题&#xff0c;1和5的后缀值都为 -1…

【MySQL进阶之路 | 高级篇】简述Bin Log日志

1. 日志类型 MySQL有不同类型的日志文件&#xff0c;用来存储不同类型的日志&#xff0c;分为二进制日志、错误日志、通用查询日志和慢查询日志&#xff0c;这也是常用的4种。MySQL 8又新增两种支持的日志:中继日志和数据定义语句日志。使用这些日志文件&#xff0c;可以查看M…

树与二叉树【数据结构】

前言 之前我们已经学习过了各种线性的数据结构&#xff0c;顺序表、链表、栈、队列&#xff0c;现在我们一起来了解一下一种非线性的结构----树 1.树的结构和概念 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一…

LLM大模型在融合通信产品中的应用实践

前言 LLM 问题 幻觉&#xff1a;在没有答案的情况下提供虚假信息。 过时&#xff1a;当用户需要特定的当前响应时&#xff0c;提供过时或通用的信息。 来源&#xff1a;从非权威来源创建响应。由于术语混淆&#xff0c;不同的培训来源使用相同的术语来谈论不同的事情&#…

【Gin】智慧架构的巧妙砌筑:Gin框架中控制反转与依赖注入模式的精华解析与应用实战(下)

【Gin】智慧架构的巧妙砌筑&#xff1a;Gin框架中控制反转与依赖注入模式的精华解析与应用实战(下) 大家好 我是寸铁&#x1f44a; 【Gin】智慧架构的巧妙砌筑&#xff1a;Gin框架中控制反转与依赖注入模式的精华解析与应用实战(下)✨ 喜欢的小伙伴可以点点关注 &#x1f49d; …

Meta 发布 Llama3.1,一站教你如何推理、微调、部署大模型

最近这一两周看到不少互联网公司都已经开始秋招提前批了。不同以往的是&#xff0c;当前职场环境已不再是那个双向奔赴时代了。求职者在变多&#xff0c;HC 在变少&#xff0c;岗位要求还更高了。 最近&#xff0c;我们又陆续整理了很多大厂的面试题&#xff0c;帮助一些球友解…

古文:诸葛亮《前出师表》

前出师表 师&#xff1a;军队。 表&#xff1a;就是“奏表”&#xff0c;又称“表文”&#xff0c;是臣属给君王的上书。古代给君王的上书&#xff0c;有各种名称&#xff0c;不同的名称与上书内容有关。刘勰《文心雕龙章表》云&#xff1a;“章以谢恩&#xff0c;奏以按劾&a…

高速板开源项目学习(二)

一定要找一个高速板写的详细的等长规范&#xff1a; 看的出来&#xff0c;这位小哥也是卡着嘉立创最小免费钻孔大小来打孔的&#xff1a; 这里的天线&#xff0c;他做了禁止铺铜和走线处理&#xff0c;模拟信号在这里容易遇到干扰&#xff0c;这样是正确的&#xff0c;值得去学…

解决使用selenium-wire访问链接地址不安全的问题

pip安装selenium-wire 描述&#xff1a;这里用的是python3.12.2 selenium-wire5.1.0 pip3.12 install selenium-wire pip3.12 install blinker1.7 pip3.12 install setuptools 运行以下命令来获取证书 python -m seleniumwire extractcert 安装浏览器ssl证书 Windows上给…

【JavaScript】延迟加载 js 脚本

defer 属性&#xff1a;在 HTML 中通过设置 script 标签的 defer 属性来实现脚本的延迟加载&#xff0c;即脚本的下载与 HTML 的解析不会阻塞彼此&#xff0c;脚本会在 HTML 解析完成后才执⾏。async 属性&#xff1a;在 HTML 中通过设置 script 标签的 async 属性来实现脚本的…

深入理解 Java NIO:ByteBuffer和MappedByteBuffer的特性与使用

目录 前言 ByteBuffer是什么 重要特点 分配缓冲区 读写模式切换 操作文本数据 操作基本数据类型 案例解析-循环输出数据 MappedByteBuffer是什么 MappedByteBuffer 的工作机制 刷盘时机 总结 前言 在深入学习 RocketMQ 这款高性能消息队列框架的源码时&#xff0c…

免费【2024】springboot 畅游游戏销售平台

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

EchoMimicV2,Audio Driven加速模型,推理速度大幅提升

EchoMimic更新啦&#xff0c;我24号刚出的一篇&#xff0c;到了25号官方就更新了新的加速模型。 着实没赶上官方更新的速度...... 那本次我主要讲下更新了什么内容&#xff0c;如何修改使用acc加速模型。 另外还准备了v2版本的整合包&#xff01;大家可以体验下&#xff01; 更…

ProxmoxPVE虚拟化平台--安装PVE虚拟机

Proxmox 虚拟机 Proxmox是一个基于Debian Linux和KVM的虚拟化平台&#xff0c;‌它提供了虚拟化的环境&#xff0c;‌允许用户在同一台物理机上运行多个虚拟机。‌Proxmox虚拟环境&#xff08;‌PVE&#xff09;‌是一个开源项目&#xff0c;‌由Proxmox Server Solutions Gmb…

从与原始的Transformer architecture比较来理解GPT

从与原始的Transformer architecture比较来理解GPT flyfish 一、Transformer architecture 先说名词 不同的文献和资料中有不同的名字&#xff0c;其实是一样的意思 1 编码器-解码器多头注意力机制&#xff08;Encoder-Decoder Multi-Head Attention Mechanism&#xff09; …

CI/CD:Job failed: execution took longer than 1h0m0s seconds

简介&#xff1a;当在CI/CD配置运行Gitlab-runner流水线中&#xff0c;一般默认情况下&#xff0c;Job的执行时间默认为1小时&#xff0c;如果超出1小时&#xff0c;任务会中断。 历史攻略&#xff1a; 定时任务&#xff1a;Jenkins 容器化CICDLocust性能压测 容器化CICDSo…

我的NAS是怎么连接Amazon Web Services S3的

作为IT爱好者&#xff0c;很多家庭都配备了Network Attached Storage&#xff08;NAS&#xff09;&#xff0c;用于存储和管理大量数据。一个常见的挑战是如何实现异地备份&#xff0c;以确保数据的安全性和可恢复性。以下是一些解决方案和工具&#xff0c;可以帮助用户有效地管…