java虚拟机


JVM的运行机制

运行过程

  1. Java源文件被编译器编译成字节码文件
  2. JVM将字节码文件编译成相应操作系统的机器码
  3. 机器码调用相应操作系统的本地方法库执行相应的方法

628116210.jpg
类加载器用于将编译好的.Class文件加载到JVM中
即时编译器:将Java字节码编译成具体的机器码

多线程

JVM的线程与操作系统中的线程是相互对应的,在JVM线程的本地存储、缓冲区分配、同步对象、栈、程序计数器等准备工作都完成时,JVM会调用操作系统的接口创建一个与之对应的原生线程;在JVM线程运行结束时,原生线程随之被回收。
操作系统负责调度所有的线程,并为其分配CPU时间片,在原生线程初始化完毕后,就会调用Java线程的run()执行该线程;在线程结束时,会释放原生线程和Java线程对应的资源

在Jvm后台运行的线程主要有

  1. 虚拟机线程(JVM Thread) 虚拟机线程在JVM到达安全点时出现
  2. 周期性任务线程:通过定时器调度线程来实现周期性操作的执行
  3. GC线程:支持JVM中不同的垃圾回收活动
  4. 编译器线程:在运行时将字节码动态编译成本地平台机器码,是JVM跨平台的具体体现
  5. 信号分发线程:接收发送到JVM的信号并调用JVM方法

JVM的内存区域


线程私有区域

生命周期与线程相同,在JVM内,每个线程都与操作系统的本地线程直接映射,这部分区域的存在与否和本地线程的启动和销毁对应

程序计数器:线程私有,无内存溢出问题

一块很小的内存空间,用于存储当前运行的线程所执行的字节码的型号指示器
每个运行中的线程都有一个独立的程序计数器,在方法正在执行时,该方法的程序计数器记录的是实时虚拟机字节码指令的地址;如果该方法执行的是Native方法,则值为空
它是唯一没有内存溢出的区域

虚拟机栈:线程私有,描述Java方法的执行过程

描述Java方法的执行过程的内存模型,它在当前栈帧中存储了局部变量表,操作数栈,动态链接,方法出口等,也用来存储部分运行时数据及其数据结构,处理动态链接方法的返回值和异常分派

本地方法区:线程私有

和虚拟机栈作用类似,但是为Native方法服务

线程共享区

随虚拟机的启动而创建,随虚拟机的关闭而销毁

堆:线程共享

也被称为【运行时数据区】,是垃圾回收期进行垃圾回收的最主要的内存区域
堆从GC【GarbageCollection 垃圾回收】可细分为:新生代、老年代、永久代

方法区: 线程共享

也被称为永久代,存储常量、静态变量、类消息、即时编译器编译后的机器码、运行时常量池等数据
JVM使用java堆的永久代来实现方法区,这样JVM的垃圾收集器就可以像管理java堆一样管理这部分内存。永久代的内存回收主要针对常量池的回收和类的卸载,可回收的对象很少
常量被存储在运行时常量池中,是方法区的一部分

直接内存

也叫对外内存, 并不是JVM运行时数据区的一部分,但在并发编程中被频繁使用。
JDK的NIO模块提供的Channel与Buffer的I/O操作方式就是基于对外内存实现的,NIO模块通过调用Native函数库直接在操作系统上分配对外内存,然后使用DirectByteBuffer对象作为这块内存的引用对内存进行操作,Java进程可以通过对外内存技术避免在java堆和Native堆中来回复制数据带来的资源占用和性能消耗,因此堆外内存在高并发应用场景下被广发使用

JVM的运行时内存(JVM堆)

1741625077.jpg

新生代

JVM新创建的对象(除了大对象以外)会被放在新生代,由于JVM会频繁创建对象,所以新生代会频繁触发MinorGC(新生代的GC过程)进行垃圾回收

MinorGC过程,采用复制算法:
  1. 把在Eden区和ServivorFrom区中存活的对象复制到ServivorTo区。

如果某对象的年龄达到老年代的标准(由XX:MaxTenuringThreshold设置,默认为15),则将其复制到老年代,同时把他们年龄+1,
如果对象属于大对象(2KB~128KB),也复制到老年代

  1. 清空Eden区和ServivorFrom区中的对象
  2. 将ServivorTo区和ServivorFrom区互换
Eden区

新创建的对象会首先放在 Eden区,如果新创建的对象属于大对象(一般为2KB~128KB),则分配到老年代
在Eden区内存不足时,触发MinorGC,对新生代进行垃圾回收

ServivorTo区

保留上一次MinorGC时的幸存者

ServivorFrom区

将上一次MinorGC时的幸存者作为这一次的被扫描者

老年代

存放有长生命周期的对象和大对象。老年代的GC叫MajorGC。
对象比较稳定,MajorGC不会频繁触发。

在进行MajorGC前,JVM会进行MinorGC,如果之后还是存在老年代空间不足或无法找到足够大的连续空间分配给新创建的大对象时,会触发MajorGC进行垃圾回收,释放JVM的内存空间

MajorGC采用标记清除算法,该算法首先会扫描所有对象并标记存活的对象,然后回收未被标记的对象,并释放内存空间
因为要先扫描老年代的所有对象再回收,所以MajorGC耗时较长。MajorGC的标记清楚算法容易产生内存碎片。老年代没有内存分配时,会抛出Out Of Memory

永久代

主要存放Class和Meta(元数据),Class在类加载时被放入永久代。GC不会再程序运行期间对永久代清理内存,导致了永久代的内存会随着Class的增多而变多,过多时会抛出Out Of Memory
Java8以后,永久代被【元数据区(元空间)】取代,区别在:元数据区直接使用操作系统的本地内存,不受JVM内存的限制,之和操作系统的内存有关
Java8中,JVM将 元数据放入本地内存中,常量池和类的静态变量放入Java堆中

垃圾回收与算法

如何确定垃圾

-1551785530.jpg

  1. 引用计数法

给对象中添加一个引用计数器:

  • 每当有一个地方引用它,计数器就加 1;
  • 当引用失效,计数器就减 1;
  • 任何时候计数器为 0 的对象就是不可能再被使用的。

这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间循环引用的问题。

两个对象相互引用

public class ReferenceCountingGc {
    Object instance = null;
    public static void main(String[] args) {
        ReferenceCountingGc objA = new ReferenceCountingGc();
        ReferenceCountingGc objB = new ReferenceCountingGc();
        objA.instance = objB;
        objB.instance = objA;
        objA = null;
        objB = null;
    }
}
  1. 可达性分析

通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,如果在GC Roots和一个对象之间没有可达路径,则称该对象是不可达的,不可达对象要经过至少两次标记才能判定其是否可以被回收,如果在两次标记后仍然是不可达的,就应该被回收
下图中的 Object 6 ~ Object 10 之间虽有引用关系,但它们到 GC Roots 不可达,因此为需要被回收的对象。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

垃圾回收算法

-662442343.jpg

标记清除算法

最基础的算法
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
清理后并没有整理可用的空间,所以会引起碎片化的问题,继而引起大对象无法获得连续可用空间的问题

复制算法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。
虽然改进了标记-清除算法,但依然存在下面这些问题:

  • 可用内存变小:可用内存缩小为原来的一半。
  • 不适合老年代:如果存活对象数量比较大,复制性能会变得很差。
标记整理算法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
根据老年代的特点提出的一种标记算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。
由于多了整理这一步,因此效率也不高,适合老年代这种垃圾回收频率不是很高的场景。

分代收集算法
当前虚拟机的垃圾收集都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将 Java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。<br />在新生代中,每次收集都会有大量对象死去,选择”标记-复制“算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。<br />老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。

分区收集算法

将整个堆空间划分为连续的大小不同的小区域,对每个小区域都单独进行内存使用和垃圾回收,好处是能根据每个小区域内存的大小灵活使用和释放内存
可以根据系统可接受的停顿时间,每次都快速回收若干个小区域的内存,以缩短垃圾回收时,系统停顿的时间,最后以多次并行累加的方式逐步完成整个内存区域的垃圾回收

垃圾收集器


Serial

在它进行垃圾收集时,必须暂停其他所有工作线程,直到垃圾收集结束
对于单CPU环境来说,没有线程交互开销,可以获得最高的单线程垃圾收集效率
JVM运行在Client模式下的新生代的默认垃圾收集器

ParNew

是Serial的多线程实现,在它进行垃圾收集时,必须暂停其他所有工作线程,直到垃圾收集结束
是JVM运行在Server模式下新生代的默认垃圾收集器

Parallel Scavenge

为提高新生代垃圾收集器收集效率而设计的垃圾收集器,通过自适应调节策略优化了系统吞吐量,提供了三个参数用于调节

  1. -XX:MaxGCPauseMillis 控制最大垃圾收集停顿时间
  2. -XX:GCTimeRadio 控制吞吐量大小
  3. UseAdaptiveSizePolicy 控制自适应调节策略开启与否

CMS

Concurrent Mark Sweep
达到最短的垃圾回收停顿时间image.png

  1. 初始标记

只标记和GC Roots直接关联的对象,速度很快,需要"Stop The World"

  1. 并发标记

和用户线程一起工作,执行GC Roots跟踪标记过程,不需要暂停工作线程

  1. 重新标记

在并发标记过程中用户线程继续运行,导致在垃圾回收过程中部分对象的状态发生变化,为了确保这部分对象的状态正确性,需要对其重新标记并暂停工作线程

  1. 并发消除

和用户线程一起工作,执行清除GC Roots不可达对象的任务,不需要暂停线程

Serial Old

Serial垃圾收集器的老年代实现
image.png

Parallel Old

优先考虑系统吞吐量、其次考虑停顿时间等因素
image.png

G1

Garbage First
为了避免全区域垃圾收集引起的系统停顿,将堆内存划分为大小固定的几个独立区域,独立使用这些区域的内存资源并且跟踪这些区域的垃圾收集进度,同时在后台维护一个优先级列表,在垃圾回收过程中根据系统允许的最长垃圾收集时间,优先回收垃圾最多的区域
G1通过内存区域独立划分使用和根据不同优先级回收各区域垃圾的机制,确保了G1在有限时间内获得最高的垃圾收集效率
相对于CMS,有以下优点

  1. 基于标记整理算法,不产生内存碎片
  2. 可以精确的控制停顿时间,在不牺牲吞吐量的前提下实现短停顿垃圾回收

类加载机制

类加载阶段

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

加载

JVM读取Class文件,并且根据Class文件描述创建java.lang.Class对象的过程
类加载过程主要包含将Class文件读取到运行时区域的方法区内,在堆中创建java.lang.Class对象,并封装类在方法区的数据结构的过程,在读取Class文件时既可以以文件的形式读取,也可以用过jar包、war包读取,还可以通过代理自动生成Class或其他方式读取

验证

确保Class文件符合当前虚拟机的要求,保障虚拟机自身的安全,只有通过验证的Class文件才能被JVM加载

准备

在方法区中为类变量分配内存空间并设置类中变量的初始值(不同数据类型的默认值)

final类型与否的初始化过程不同
public static long value = 1000;
静态变量在准备阶段的初始值是0,将value设置为1000的动作是在对象的初始化中完成的,因为JVM在编译阶段会将静态变量的初始化操作定义在构造器中
public static final int value = 1000;
JVM在编译阶段后会为final类型的变量value生成其对应的ConstantValue属性,虚拟机在准备阶段会根据ConstantValue属性将value赋值为1000

解析

JVM会将常量池中的符号引用替换为直接引用

初始化

主要通过类构造器的方法为类进行初始化
方法是在编译阶段由编译器自动收集类中静态语句块和变量的赋值操作组成的,JVM规定,只有在父类的方法都执行成功后,子类中的方法才可以被执行
在一个类中既没有静态变量赋值操作也没有静态语句块时,编译器不会为该类生成方法

发生以下几种情况,JVM不会执行初始化流程

  1. 常量在编译时会将其常量值存入使用该常量的类的常量池中,该过程不需要调用常量所在的类
  2. 在子类引用父类的静态字段时,不会触发子类的初始化,只会出发父类的初始化
  3. 定义对象数组
  4. 使用类名获取Class对象时
  5. 使用Class.forName加载指定的类时,可以通过initialize参数设置是否需要对类进行初始化
  6. 使用ClassLoader默认的loadClass方法加载类时

类加载器外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

启动类加载器

负责加载Java_HOME/lib目录中的类库,或通过-Xbootclasspath参数指定路径中被虚拟机认可的类库

扩展类加载器

负责加载Java_HOME/lib/ext目录中的类库,或通过java.ext.dirs系统变量加载指定路径中的类库

应用程序类加载器

负责加载用户路径(classpath)上的类库

还可以通过继承java.lang.ClassLoader实现自定义的类加载器

双亲委派机制

一个类在收到类加载请求后不会尝试自己加载这个类,而是把请求向上委派其父类完成,父类又会委派给自己的父类,所有的类加载请求都被向上委派到了启动类加载器中
若父类加载器在接收到类加载请求后发现自己也无法加载该类(通常原因是该类的class文件在父类的类的加载路径中不存在),则父类会将该信息反馈给子类并向下委派子类加载器加载该类,直到该类被成功加载,否则抛出ClassNotFound异常
image.png

  1. 将自定义加载器挂在到应用程序类加载器
  2. 应用程序类加载器将类加载请求委托给扩展类加载器
  3. 扩展类加载器将类加载请求委托给启动类加载器
  4. 启动类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交由扩展类加载器加载
  5. 扩展类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交由应用程序类加载器加载
  6. 应用程序类加载器在加载路径下查找并加载Class文件,如果未找到目标Class文件,则交由自定义类加载器加载
  7. 在自定义加载器下查找并加载Class文件,如果未找到目标Class文件,抛出ClassNotFound异常

核心是唯一性和安全性。
比如 加载rt.jar包中的java.lang.Object类时,无论那个类加载器加载这个类,最终都将类请求委托给了启动类加载器加载,就保证了类加载的唯一性,如果重名,则类无法被加载

OGSI

Open Service Gateway Initialtive是Java动态化模块化系统的一系列规范,旨在为实现Java程序的模块化编程提供基础条件
基于OSGI的程序可以实现模块级的热插拔功能,只针对需要更新的程序进行停用和重新安装

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小米开放式耳机怎么样?小米、西圣、漫步者王者pk测评角逐

我们常说的开放式耳机&#xff0c;就是一种采用开放式设计的音频设备&#xff0c;能够给用户带来更加自然且广阔的音质体验&#xff0c;相比与传统的入耳式耳机&#xff0c;开放式耳机无需入耳&#xff0c;在佩戴方面更加的舒适&#xff0c;在音质方面开放式耳机的听感会更加自…

Flat Ads:金融APP海外广告投放素材的优化指南

在当今全球化的数字营销环境中,金融APP的海外营销推广已成为众多金融机构与开发者最为关注的环节之一。面对不同地域、文化及用户习惯的挑战,如何优化广告素材,以吸引目标受众的注意并促成有效转化,成为了广告主们亟待解决的问题。 作为领先的全球化营销推广平台,Flat Ads凭借…

如何保证语音芯片的稳定性能和延长使用寿命

要让语音芯片保持稳定性能&#xff0c;首先需要深入理解其工作原理和内部构造。语音芯片&#xff0c;作为现代电子设备中的核心组件之一&#xff0c;承载着声音信号的处理与输出功能。为了确保其稳定运行&#xff0c;我们需要从多个方面进行细致的考虑和操作。‌ 1、避免长期高…

【数据结构】初探数据结构面纱:栈和队列全面剖析

【数据结构】初探数据结构面纱&#xff1a;栈和队列全面剖析 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;数据结构 文章目录 【数据结构】初探数据结构面纱&#xff1a;栈和队列全面剖析前言一.栈1.1栈的概念及结构1.2栈的结构选择1.3栈的…

数据结构(3.9_1)——特殊矩阵的压缩存储

总览 一维数组的存储结构 如果下标从1开始&#xff0c;则a[i]的存放地址LOC (i-1)*sizeof(ElemType); 二维数组的存储 二维数组也具有随机存储的特性 设起始地址为LOC 在M行N列的二维数组b[M][N]中&#xff0c;若按行优先存储&#xff0c; 则b[i][j]的存储地址的LOC (i*…

【JVM】对象的生命周期一 | 对象的创建与存储

Java | 对象的生命周期1-对象的创建与存储 文章目录 前言对象的创建过程内存空间的分配方式方式1 | 指针碰撞方式2 | 空闲列表 线程安全问题 | 避免空间冲突的方式方式1 | 同步处理&#xff08;加锁)方式2 | 本地线程分配缓存 对象的内存布局Part1 | 对象头Mark Word类型指针 P…

文献翻译与阅读《Integration Approaches for Heterogeneous Big Data: A Survey》

CYBERNETICS AND INFORMATION TECHNOLOGIES’24 论文原文下载地址&#xff1a;原文下载 目录 1 引言 2 大数据概述 3 大数据的异构性 4 讨论整合方法 4.1 大数据仓库&#xff08;BDW&#xff09; 4.2 大数据联盟&#xff08;BDF&#xff09; 5 DW 和 DF 方法的比较、分…

智充科技营收增速放缓:经营成本飙升,应收账款大幅增长

《港湾商业观察》黄懿 6月10日&#xff0c; XCHG Limited 智能充电有限公司(下称&#xff1a;智充科技)在美国证监会(SEC)更新招股书&#xff0c;拟在美国纳斯达克上市&#xff0c;其股票代码为“XCH”。北京智充科技有限公司为其国内运营主体&#xff08;下称“北京智充科技”…

IC后端设计中的shrink系数设置方法

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 在一些成熟的工艺节点通过shrink的方式(光照过程中缩小特征尺寸比例)得到了半节点,比如40nm从45nm shrink得到,28nm从32nm shrink得到,由于半节点的性能更优异,成本又低,漏电等不利因素也可以…

C++学习

一、注释 /*多行 。。。 。。。 注释*/ //单行注释 #include <iostream> using namespace std; int main() {cout << "hellow" << endl;system("pause");return 0; }二、变量定义 #include <iostream> using namespace std; int…

YOLOv8改进 | 注意力机制| 利用并行子网络构建深度较浅但性能卓越的网络【全网独家】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

[PM]原型与交互设计

原型分类 1.草图原型 手绘图稿, 规划的早期,整理思路会使用 2.低保真原型 简单交互, 无需配色, 黑白灰为主, 产品规划和评审阶段使用 标准化的低保真原型是高保真原型的基础 3.高保真原型 复杂交互, 一般用于公开演示, 产品先产出低保真原型, 设计师根据原型产出设计稿 低保…

【ARM】CCI缓存一致性整理

目录 1.CCI500提供的功能 2.CCI500在SOC系统中所处的位置​编辑 3.CCI500内部结构​编辑 4.功能描述 1.CCI500提供的功能 2.CCI500在SOC系统中所处的位置 3.CCI500内部结构 Transaction Tracker&#xff08;TT&#xff09;是用来解决一致性和ordering问题的&#xff0c;它…

【驱动篇】龙芯LS2K0300之spi设备驱动

实验介绍 GC9A01是一款小巧&#xff08;1.28寸&#xff09;、彩色&#xff08;分辨率为 240 * 240 RGB&#xff09;圆形TFT屏幕&#xff0c;它采用4线 SPI的控制方式&#xff0c;电源供电电压为3.3V&#xff0c;有7个控制引脚&#xff1b;本次实验将使用它来验证龙芯SOC的SPI通…

css实现图片渐变切换效果

一、效果 使用csskeyframes&#xff0c;实现5个图片渐变切换的效果。如下图&#xff1a; 二、代码 1.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"w…

头歌资源库(27)特别的数

一、 问题描述 编程输出一个特别的数&#xff0c;该数是一个由1~9组成的9位数&#xff0c;每个数字只能出现一次&#xff0c;且这个9位数由高位到低位前i位能被i整除。 二、算法思想 创建一个长度为9的数组&#xff0c;用于存放1~9这9个数字。使用回溯算法&#xff0c;从第…

(WRF-UCM)高精度城市化气象动力模拟技术

气候变化及应对是政府、科学界及商业界关注的焦点。气候是多个领域&#xff08;生态、水资源、风资源及碳中和等问题&#xff09;的主要驱动因素&#xff0c;合理认知气候变化有利于解释生态环境变化机理及过程&#xff0c;而了解现在、未来气候变化则是进行生态、环境及能源评…

IDEA中配置代理,解决Codearts Snap登陆不了的问题

问题描述&#xff1a;在mac电脑中的idea中安装了华为的codearts snap插件&#xff0c;一直登录不了&#xff0c;账号是没问题的&#xff0c;后来我怀疑是我的代理有问题&#xff0c;找到IDEA中的代理设置先是有这个问题“You have JVM property "https.proxyHost" se…

C++基础(一)

目录 1.不同版本的hello word&#xff01; 2.namespace和&#xff1a;&#xff1a;域作用限定符以及using 2.1 namespace 2.2&#xff1a;&#xff1a; 2.3using用于展开域 3.C输入和输出 4.缺省参数 5.重载 6.引用 6.1引用介绍 6.2 引用的特性 注意&#xff1a; 6.4 c…

C#绘制阻抗圆图初步

阻抗圆图&#xff0c;或者叫史密斯图&#xff0c;是无线电设计方面用的&#xff1b; 基本的阻抗圆图如下&#xff0c; 下面尝试用C#能不能画一下&#xff1b; 先在网上找一个画坐标的C#类&#xff0c;它的效果如下&#xff1b; 自己再增加一个函数&#xff0c;可以绘制中心在…