拿捏---JVM原理

文章目录

  • JVM内存划分
  • JVM类加载
    • 为什么需要类加载?
    • 类加载的过程
    • 何时触发类加载?
    • 双亲委派模型
  • JVM的垃圾回收机制(GC)
    • 什么是垃圾回收?
    • GC回收哪部分内存?
    • 回收机制
      • 怎么找出垃圾?
        • 引用计数
        • 可达性分析(JVM采用)
      • 怎么清理垃圾?
        • 标记清除
        • 复制算法
        • 标记整理
        • 分代回收

JVM是Java程序运行的基础,整个JVM的体系结构非常复杂,但是幸运的是经常使用到的只有三个部分:内存划分、类加载和垃圾回收机制。我们接下来就向大家详细的介绍JVM里对于这三部分的具体实现:

JVM内存划分

Java程序是一个名字为Java的进程,这个进程就是所说的“JVM”。在Java程序运行前,JVM就会先向操作系统申请一大块内存空间,这个内存空间内部又划分为几个不同的部分:

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

注:

  1. 栈:存放的是方法之间的调用关系
  2. 堆:存放程序中创建的所有对象(编译后未加载好的对象)
  3. 方法区:存放类对象(编译后加载好的对象)
  4. 程序计数器:存放下一个要执行的指令的地址
  5. 在java1.7之后,将方法区换成了元数据区;即在原本的方法区内部又划分了不同的区域
  6. 在一个JVM进程中,堆区和方法区只有一份,所有线程共用;栈区和程序计数器,每个线程都有自己的一份
  7. 同时,栈:存放局部变量;堆:存放成员变量;方法区:存放静态变量。

JVM类加载

为什么需要类加载?

Java程序在运行之前需要先编译,由 .jaca 文件编译为 .class 文件(二进制字节码文件),运行的时候 JVM 就会读取相应的 .class 文件并解析其中的内容,在内存中构造出类对象并进行初始化。

类加载的过程

  • 加载

    找到 .class 文件,读取文件内容并按照 .class 规范的格式来解析

  • 连接

    • 验证

      检查当前 .class 文件里的内容格式是否符合要求

    • 准备

      给类里的静态变量分配内存空间

    • 解析

      初始化字符串常量:把符号引用(占位符)替换成直接引用(内存地址)

      比如:代码中有一行 String s = “hello”;在类加载之前 “hello” 这个字符串常量没有分配内存空间,没有内存空间 s 也就无法保存 “hello” 的真正的地址,只能用占位符标记一下;等给 “hello” 分配内存空间后,再用真正的地址来替换之前的占位符。

  • 初始化

    针对类进行初始化,初始化静态成员、执行静态代码块、加载父类。

何时触发类加载?

使用到一个类的时候就要触发类加载(类并不是程序一启动就加载了,而是在第一次被使用的时候才会加载)

比如:

  1. 创建了这个类的实例
  2. 使用了类的静态方法、静态属性
  3. 使用了类的子类(加载子类会触发加载父类)

双亲委派模型

双亲委派模型:决定了按照啥样的规则到哪些目录下去找 .class 文件

JVM加载类是由类加载器(class loader)这样的模块来负责的,JVM自带了多个类加载器:

  1. Bootstrap ClassLoader:负责加载标准库中的类
  2. Extension ClassLoader:负责加载JVM扩展的库的类
  3. Application ClassLoader:负责加载项目里自定义的类

在这里插入图片描述

注:

  1. 上述三个类加载器具有父子关系
  2. 进行类加载的时候,输入的内容是 全限定类名 形如:java.lang.Thread
  3. 加载的时候从 Application ClassLoader 开始
  4. 某个类加载器加载的时候,不会立即扫描自己负责的路径,而是先把任务委派给父“类加载器”来先进行处理
  5. 找到最上面的 Bootstrap ClassLoader 再往上就没有父类加载器了,只能自己动手加载
  6. 如果父类没有找到类,就交给自己的儿子继续加载
  7. 如果一直找到最下面的 Application ClassLoader 也没有找到类,就会抛出一个“类没有找到”的异常,类加载也就失败了。

按照这个顺序加载最大的好处就是:如果我们自己写了个类,正好全限定类名和标准库中的类冲突了(类名一样),此时进行类加载就能保证加载到标准库中的类,防止代码加载错了带来问题。

JVM的垃圾回收机制(GC)

什么是垃圾回收?

我们的内存空间是有限的,如果只申请内存空间但是不释放就会造成很严重的问题。而垃圾回收机制呢就是:让JVM自动判定你申请的内存啥时候需要释放,即当JVM认为这块内存不再被使用了就会释放。

这样的机制可以减轻程序员的负担也能更好的避免忘记释放内存空间的问题,毕竟程序员只负责申请内存空间即可,释放内存空间的工作交给了JVM来完成。

GC回收哪部分内存?

栈:存放方法间的调用关系----------释放时机确定,不必回收
堆:存放程序中所有的对象----------GC进行回收
方法区:存放加载好的类 ----------加载好后不需要回收
程序计数器:存放下一条指令的地址---------是一块固定的内存空间,不必回收

回收机制

怎么找出垃圾?

如果一个对象再也不被使用了,那么它就是垃圾。
在Java中,对象的使用需要凭借引用。如果一个对象已经没有任何一个引用可以指向它,那么它就无法被使用,就变成了垃圾。

所以:我们要通过引用来判断当前对象是否还能被使用,没有引用就代表无法使用。我们下面介绍两种判断引用是否存在的方法:

引用计数

引用计数:给每个对象都加一个计数器,通过这个计数器来表示“当前对象具有几个引用”

每多一个引用指向该对象,计数器就+1;每少一个引用指向该对象,计数器就-1;
当计数器数值为0的时候,就证明当前对象没有引用了、不能被使用了、可以被释放了。

引用计数:

优点: 简单、容易实现、执行效率高

缺点:

  1. 空间利用率比较低。(如果对象里只存一个int的数值,此时还需要再引入一个int的计数器,计数器所占的比重就太大了)
  2. 可能会出现循环引用的情况。(虽然当前有两个对象的计数器都为1,但是是这两个对象在相互引用,并没有别的引用指向他俩。此时他俩本应该被释放的,但是现在不能释放)
可达性分析(JVM采用)

约定一些特定的对象作为(GC roots),每隔一段时间,从 GC roots 出发进行遍历,看看当前哪些对象是能被访问到的。能被访问到的对象就称为“可达”;访问不到的对象就称为“不可达”。包含“可达”对象的类不做处理,包含“不可达”对象的类要被确定为垃圾。

在这里插入图片描述

注: 可以设为 GC roots 的对象有:

  1. 栈中引用的对象
  2. 方法区中常量引用的对象
  3. 方法区中静态属性引用的对象

怎么清理垃圾?

标记清除

在这里插入图片描述
灰色的部分被标记为“垃圾”。标记出垃圾之后,直接把对象对应的内存空间释放。

缺点:内存碎片化。会导致整个内存“支离破碎”,假设总内存空间为9k(全部被使用),每块被释放的空间(灰色区域)为1k。清理垃圾后释放出4k的空闲空间,但是如果想要申请2k的内存空间会申请失败。因为现在空闲的空间都是分离的,申请空间时要得到连续的内存空间

复制算法

在这里插入图片描述

在申请内存空间的时候直接申请想要空间大小的2倍,并把这块内存空间分为俩部分(左侧和右侧),使用左侧空间时,右侧不用;使用右侧空间时,左侧不用。

在回收垃圾时,不再是原地释放了,而是把“非垃圾”(可以继续使用的对象)拷贝到另一侧,然后再把之前使用的这一半空间整个释放掉。

优点:解决了内存碎片化问题
缺点:

  1. 空间利用率更低了(使用一半空间一半)
  2. 如果这一轮GC,大部分对象都要保留,只有小部分对象需要回收,复制的开销非常大
标记整理

在这里插入图片描述

像顺序表的删除元素一样,进行搬运操作。如果前面的一小块内存空间被释放掉,则把它后面的数据依次向前搬运,占用掉已经释放了的这块内存空间。

优点:

  1. 解决了内存碎片化问题
  2. 提高了空间利用率

缺点:搬运操作的消耗也很大

分代回收

在这里插入图片描述

分代回收,是对上面三种算法的综合应用:

  1. 将对象按照不同的年龄放入到不同的区域,针对不同的区域采用不同的回收方式。其中,对象的年龄是指该对象经历的GC的轮次,经历过一次GC对象的年龄就+1。
  2. 根据对象的年龄,把对象分为新生代(年龄小的对象)和老年代(年龄大的对象)
  3. 新生代GC的扫描频率较高;老年代GC的扫描频率较低。(根据一个基本规律:如果一个对象的寿命比较长,那么它大概率还要活的更久。换句话说,要死早死了)
  4. 刚创建出来的新对象进入伊甸区。如果新对象熬过一轮GC,就通过复制算法,复制到生存区中。(绝大多数新对象都熬不过一轮GC)
  5. 生存区中的对象也要继续经历GC的考验。每熬过一轮GC就通过复制算法拷贝到另一个生存区中,只要这个对象不消亡就会在两个生存区之间来回拷贝。(每一轮GC都会杀死一大波对象)
  6. 如果一个对象在生存区中反复坚持了很多轮都没有消亡,就把它放到老年代中
  7. 在老年代中的对象通过标记整理的方式来杀死(老年代中GC扫描的频率比较低)

特殊情况: 如果对象是一个非常大的对象,则直接放入老年代
因为:

  1. 大的对象进行复制算法的时候开销太大了
  2. 大的对象创建出来相对较难,好不容易创建出来后不会让它轻易的销毁。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

物流实时数仓:数仓搭建(ODS)

系列文章目录 物流实时数仓:采集通道搭建 物流实时数仓:数仓搭建 文章目录 系列文章目录前言一、IDEA环境准备1.pom.xml2.目录创建 二、代码编写1.log4j.properties2.CreateEnvUtil.java3.KafkaUtil.java4.OdsApp.java 三、代码测试总结 前言 现在我们…

大模型推理加速框架vllm部署的实战方案

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

堆的实现(堆的插入、堆的删除等)超级全

堆的实现(堆的插入、堆的删除等)超级全 文章目录 堆的实现(堆的插入、堆的删除等)超级全一、前期基础知识1.树结构①树的定义②树的相关概念③二叉树④满二叉树和完全二叉树a.满二叉树b.完全二叉树 ⑤二叉树的性质⑥二叉树顺序结构…

YOLOv8改进 | 2023 | LSKAttention大核注意力机制助力极限涨点

论文地址:官方论文地址 代码地址:官方代码地址 一、本文介绍 在这篇文章中,我们将讲解如何将LSKAttention大核注意力机制应用于YOLOv8,以实现显著的性能提升。首先,我们介绍LSKAttention机制的基本原理,…

深入理解 Django 中的事务管理

概要 在数据库操作中,事务是确保数据完整性和一致性的关键机制。Django 作为一个强大的 Python Web 框架,提供了灵活而强大的事务管理功能。理解和正确使用 Django 中的事务对于开发高质量的 Web 应用至关重要。本文将深入探讨 Django 的事务管理机制&a…

2021年12月 Scratch(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

Scratch等级考试(1~4级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 执行下列程序,屏幕上可以看到几只小猫? A:1 B:3 C:4 D:0 答案:B 第2题 下列程序哪个可以实现:按下空格键,播放完音乐后说“你好!”2秒? A: B: C:

人工智能-注意力机制之注意力汇聚:Nadaraya-Watson 核回归

查询(自主提示)和键(非自主提示)之间的交互形成了注意力汇聚; 注意力汇聚有选择地聚合了值(感官输入)以生成最终的输出。 本节将介绍注意力汇聚的更多细节, 以便从宏观上了解注意力机…

SpringCloud实用-OpenFeign整合okHttp

文章目录 前言正文一、OkHttpFeignConfiguration 的启用1.1 分析配置类1.2 得出结论,需要增加配置1.3 调试 二、OkHttpFeignLoadBalancerConfiguration 的启用2.1 分析配置类2.2 得出结论2.3 测试 附录附1:本系列文章链接附2:OkHttpClient 增…

1|1111

1、指定在每天凌晨4:00将该时间点之前的系统日志信息(/var/log/messages )备份到目录下/backup,备份后日志文件名显示格式logfileYY-MM-DD-HH-MM 2、配置ssh免密登陆:客户端主机通过redhat用户基于秘钥验证方式进行远…

数据结构——单链表(Singly Linked List)

1.链表介绍 链表是一种物理储存上非连续、非顺序的存储结构。数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。 对于上图,每一个结点都是一个结…

NFT Insider115:The Sandbox开设元宇宙Diorama快闪店,​YGG Web3 游戏峰会已开幕

引言:NFT Insider由NFT收藏组织WHALE Members、BeepCrypto联合出品,浓缩每周NFT新闻,为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据,艺术新闻类,游戏新闻类,虚拟世界类&#…

项目中如何配置数据可视化展现

在现今数据驱动的时代,可视化已逐渐成为数据分析的主要途径,可视化大屏的广泛使用便应运而生。很多公司及政务机构,常利用大屏的手段展现其实力或演示业务,可视化的效果能让观者更快速的理解结果并直观的看到数据展现。因此&#…