JVM(Java Virtual Machine)

这篇具有很好参考价值的文章主要介绍了JVM(Java Virtual Machine)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

哥几个来学 JVM 啦~~

JVM(Java Virtual Machine),EE初阶,jvm,java

 

 

目录

🌲一、JVM 执行流程( JVM 是如何运行的?)

🌳二、JVM 运行时数据区

🍦1. 堆(线程共享)

🍧2. Java 虚拟机栈(线程私有)

🍨3. 本地方法栈(线程私有)

🍩4. 程序计数器(线程私有)

🍪5. 方法区(线程共享)

🌴三、JVM 类加载(Class Loading)

🍇(一)类加载过程

🥡1. 加载(Loading)

🍱2.连接

🍘3. 初始化(Initialization)

🍈(二)双亲委派模型

🌵四、死亡对象的判断算法

🥛1. 引用计数算法

🧃2. 可达性分析

🍀五、垃圾回收算法

🦪1. 标记-清除算法

🍣2. 复制算法

🍤3.标记-整理算法

🍥4. 分代算法


JVM (Java Virtual Machine)也就是 Java 虚拟机 。

虚拟机就是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统。

🌲一、JVM 执行流程( JVM 是如何运行的?)

JVM(Java Virtual Machine),EE初阶,jvm,java

🥗1. 程序在执行之前先要把 Java 代码转换成字节码 (class 文件),JVM 首先把字节码通过一定的方式 —— 类加载器 (ClassLoader)把文件加载到内存中运行时 数据区(Runtime Data Area)

🥙2. 但字节码文件是 JVM 的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器,也就是 JVM 的执行引擎 (Execution Engine)会将字节码翻译成底层系统指令再由 CPU 去执行。

🌮3. 在执行的过程中,也需要调用其他语言的接口,如通过调用本地库接口 (Native Interface)来实现整个程序的运行。如上图所示:

🌳二、JVM 运行时数据区

JVM 运行时数据区域也叫内存布局,它由以下五个部分组成:

JVM(Java Virtual Machine),EE初阶,jvm,java

🍦1. 堆(线程共享)

堆的作用:程序中创建的所有对象(对象实例、数组)都在保存在堆中。(只要是 new 出来的对象都是存储在堆中的)

🍧2. Java 虚拟机栈(线程私有)

Java 虚拟机栈的作用:用于存储方法执行时的局部变量表、操作数栈、动态链接、方法出口等消息。每个方法在执行时都会创建一个 栈帧(Stack Frame)用于存储以上信息。因此 Java 虚拟机栈 是线程私有的

JVM(Java Virtual Machine),EE初阶,jvm,java

🍕① 局部变量表:用于存放方法参数和局部变量。

🍔② 操作栈:每个方法都会生成一个先进后出的操作栈。

🍟③ 动态链接:指向运行时常量池的方法引用。

🌭④ 方法返回地址:PC 寄存器的地址。

什么是线程私有?

由于 JVM 的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,因此在任何一个确定的时刻,一个处理器都只会执行一条线程中的指令。因此为了切换线程后能恢复到正确的执行位置,每条线程都需要独立的程序计数器,各线程之间计数器互不影响,独立存储。我们把类似这类区域称之为 “线程私有” 的内存。

🍨3. 本地方法栈(线程私有)

本地方法栈的作用:与 Java 虚拟机栈类似,用于存储本地方法的信息。

🍩4. 程序计数器(线程私有)

程序计数器的作用:用来记录当前线程执行的行号的。

如果线程正在执行的是一个 Java 方法,这个计数器记录的正是执行的虚拟机字节码指令的地址;如果正在执行的是一个 Native(本地) 方法,这个计数器的值为空。

🍪5. 方法区(线程共享)

方法区的作用:来存储虚拟机加载的类信息、常亮、静态变量、即时编译器编译后的代码等数据。

那么在了解完以上知识之后,我们来看一下以下代码:

void func() {
    Test t = new Test();
}

请指出 JVM(Java Virtual Machine),EE初阶,jvm,java 、JVM(Java Virtual Machine),EE初阶,jvm,javaJVM(Java Virtual Machine),EE初阶,jvm,java 分别处于什么 JVM 运行时数据区 的哪一部分:

JVM(Java Virtual Machine),EE初阶,jvm,java

🌴三、JVM 类加载(Class Loading)

🍇(一)类加载过程

        对于一个类,它的生命周期是这样的:

JVM(Java Virtual Machine),EE初阶,jvm,java

         其中前 5 步是固定的顺序,并且也是类加载的过程。其中的 连接(Linking)里面分三步进行,因此对于类加载来说总共分为以下几个步骤:

1. 加载

2. 连接 :① 验证        ② 准备        ③ 解析

3.初始化

我来详细地拆分一下以上步骤:

🥡1. 加载(Loading)

查找并加载类的二进制数据。这个过程可以通过类的全限定名来完成,也可以通过其他方式完成,比如使用 ClassLoader.loadClass() 方法。

在 加载(Loading)阶段,Java 虚拟机要完成以下三件事:

  • 通过一个类的全限定名来获取定义此类的二进制字节流;
  • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;
  • 在内存中生成一个代表这个类的 java.lang.Class 对象,作为方法区这个类的各种数据的访问入口。

注意:加载(Loading)只是 类加载(Class Loading)中的一个过程,它和 类加载(Class Loading)是不同的,不要弄混淆了~~

🍱2.连接

🍕① 验证(Verification):验证加载的类是否符合 Java 虚拟机规范,比如是否有正确的文件格式、是否有正确的访问权限等。

        这一阶段的目的是为了确保 Class 文件的字节流中包含的信息符合 《Java虚拟机规范》的全部要求,确保这些信息被当做代码运行后不会危害虚拟机自身的安危。

验证选项:

  • 文件格式验证
  • 字节码验证
  • 符号引用验证
  •  . . . . . . 

🍔② 准备(Preparation):为类的静态变量分配内存,并设置为初始值。

准备阶段是正式为类中定义的变量(即静态变量,被 static 修饰的变量)分配内存并设置类变量初始值阶段。

比如此时有这样一段代码:

public static int value = 123;

它是初始化 value 的 int 值为 0,而非 123。

🍟③ 解析(Resolution):将类中的符号引用转换为直接饮用。比如将类中的方法名转换为实际的内存地址。解析阶段是 Java 虚拟机将常量池内的符号引用替换为直接引用的过程,也就是初始化常量的过程。

🍘3. 初始化(Initialization)

        执行类的初始化代码,包括静态赋值和静态代码的执行,这个类如果有父类还要先加载父类。

🍈(二)双亲委派模型

        双亲委派模型是 Java 类加载器的一种工作机制。

        它是指当一个类加载器要加载一个类时,它首先不会自己尝试加载这个类,而是把这个请求委派给父类加载器去完成。每一个层次的类加载器都是如此,因此所有的加载请求最终都应该传送到最顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求(它的搜索范围中没有找到所需的类)时,子加载器才会尝试自己去完成加载。

JVM(Java Virtual Machine),EE初阶,jvm,java

其中:

  • 启动类加载器(Bootstrap Class Loader):它是 JVM 的内部组件,负责加载 Java 核心类库(如java.lang)和其他被系统类加载器所需要的类。启动类加载器是由 JVM 实现提供的,通常使用本地代码来实现。
  • 扩展类加载器(Extension Class Loader):它是 sun.misc.Launcher$ExtClassLoader 类的实例,负责加载 Java 的扩展类库(如 java.util、java.net)等。扩展类加载器通常从 java.ext.dirs 系统属性所指定的目录或 JDK 的扩展目录中加载类。
  • 系统类加载器(System Class Loader):也称为应用类加载器(Application Class Loader),它是sun.misc.Launcher$AppClassLoader 类的实例,负责加载应用程序的类。系统类加载器通常从 CLASSPATH 环境变量所指定的目录或 JVM 的类路径中加载类。
  • 用户自定义类加载器(User-defined Class Loader):这是开发人员根据需要自己实现的类加载器。用户自定义类加载器可以根据特定的加载策略和需求来加载类,例如从特定的网络位置、数据库或其他非传统来源加载类。

双亲委派模型的优点:

🍕①  避免重复加载类:比如 A 类 和 B 类 都有一个父类 C 类,那么当 A 启动时就会将 C 类 加载起来,那么在 B 类 进行加载时就不需要再重复加载 C 类了。

🍔②  更安全:使用双亲委派模型也可以保证了 Java 的核心 API 不被篡改。如果没有使用双亲委派模型,而是每个类加载器加载自己的话就会出现一些问题,比如我们编写一个称为 java.lang.Object 类的话,那么程序运行的时候,系统就会出现多个不同的 Object 类,而有些 Object 类又是用户自己提供的,因此安全性就不能得到保障了。

🌵四、死亡对象的判断算法

        在 Java 中,所有的对象都是要存在内存中的(也可以说内存中存储的是一个个对象),因此我们将内 存回收,也可以叫做死亡对象的回收。

🥛1. 引用计数算法

        引用计数器算法的实现思路是,给对象增加一个引用计数器,每当有一个地方引用它时,计数器就 + 1;当引用失效时,计数器就 - 1;任何时刻计数器为 0 的对象就是不能再被使用的,即对象已“死”。

引用计数法的优点:判定简单,判定效率也高。

引用计数法的缺点:浪费内存空间。切无法解决对象的循环引用问题。

观察循环引用问题:

①  现在我们new了两个对象出来

Test a = new Test();
Test b = new Test();

JVM(Java Virtual Machine),EE初阶,jvm,java

此时,两个对象的引用计算器都是1。

②  我们将 a 的实例指向 b,将 b 的实例指向 a

a.n = b;
b.n = a;

JVM(Java Virtual Machine),EE初阶,jvm,java

此时,a 和 b 的引用计算器的值都加 1。 

③ 然后,我们将 a 和 b 给删除掉

a = null;
b = null;
// 强制jvm进行垃圾回收
 System.gc();

JVM(Java Virtual Machine),EE初阶,jvm,java

结果就是,a 和 b 都不能被使用了,但是引用计数器都只减 1 了,这两个对象由于引用计算器不为 0 ,因此不会被当做垃圾被回收~~

🧃2. 可达性分析

        可达性分析算法是通过一系列称为 “GC Roots” 的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称之为“引用链”,当一个对象到 GC Roots 没有任何引用链相连时(从 GC Roots 到这个对象不可达)时,证明找个对象是不可用的。

JVM(Java Virtual Machine),EE初阶,jvm,java

🍀五、垃圾回收算法

🦪1. 标记-清除算法

        标记-清除(Mark-Sweep)算法是由标记阶段和记忆清除阶段构成的。标记阶段会给所有存活的对象做上标记,而清除阶段会把没有被标记的死亡对象进行回收。而标记的判断方法就是前面讲的引用计数算法和可达性分析算法。

JVM(Java Virtual Machine),EE初阶,jvm,java

优点:实现简单。

缺点:产生不连续的内存碎片,如果程序需要分配一个连续内存的大对象时,就需要提前触发一次垃圾回收。

🍣2. 复制算法

        复制算法是将内存分为大小相同的两块区域,每次只使用其中的一块区域,这样在垃圾回收时就可以直接将存活的东西复制到新的内存上,然后再把另一块内存全部清理掉。这样就不会产生碎片的问题了。

JVM(Java Virtual Machine),EE初阶,jvm,java

优点 :执行效率高,没有内存碎片的问题。

缺点:空间利用率低,因为复制算法每次只能使用一半的内存。

🍤3.标记-整理算法

        标记-整理算法是由两个阶段组成的:标记阶段和整理阶段。标记阶段会给所有存活的对象做上标记,整理阶段是把所有存活的对象移动到内存的一端,然后把另一端的所有死亡对象全部清除。

JVM(Java Virtual Machine),EE初阶,jvm,java

优点:解决了内存碎片问题,比复制算法空间利用率高。

缺点:因为有局部对象移动,所以效率不是很高。

🍥4. 分代算法

        分代算法是通过区域划分,实现不同区域和不同的垃圾回收策略,从而实现更好的垃圾回收。

        当前 JVM 垃圾回收采用的都是“分代收集(Generational Collection)”算法,这个算法并没有新思想,只是根据对象存活周期的不同将内存划分为几块。一般是把 Java 堆分为新生代和老年代。在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用复制算法。而老年代中对象存活率高。没有而外空间对它进行担保,就必须使用 “标记-清理” 或者“标记-整理”算法。特殊情况:如果对象非常大,那么直接进入老年代(大对象进行复制算法,成本太高)。

那些对象会进入新生代?那些对象会进入老年代?

  • 新生代:一般创建的对象都会进入新生代。
  • 老年代:当对象经历了 N 次(一般默认是 15 次)垃圾回收仍然存活下来的对象会从新生代移动到老年代。

为什么要将堆分成新生代和老年代呢?

        因为对象分为两种,绝大多数对象都是朝生夕灭的,也是就是用完一次之后就不用了,而剩下一部分对象是要重复使用多次的,将不同对象划分到不同的区域,不同的区域使用不同的垃圾回收算法,这样可以大大提高 Java 虚拟机的工作效率。

面试题:请问了解 Minor GC 和 Full GC 么,这两种 GC 有什么不一样吗?

①  Minor GC 又称为新生代 GC:指的是发生在新生代的垃圾收集。因为 Java 对象大多都具备朝生夕灭的特性,因此 Minor GC (采用复制算法)非常频繁,一般回收速度也比较快。

②  Full GC 又称 老年代 GC 或者 Major GC:指发生在老年代的垃圾收集。出现了 Major GC,经常会伴随至少一次的 Minor(新生代) GC (并非绝对,在 Parallel Scavenge 收集器中就有直接进行 Full GC 的策略选择过程)。Major(老年代) GC 的速度一般会比 Minor(新生代) GC 慢 10 倍以上。


        以上就是 JVM 的基础内容啦,虽然进公司之后都不会让你用到这些知识,但是面试会考呀,所以非常重要!!

JVM(Java Virtual Machine),EE初阶,jvm,java文章来源地址https://www.toymoban.com/news/detail-608427.html

到了这里,关于JVM(Java Virtual Machine)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【解决方法】各类软件启动报错:Failed to create the Java Virtual Machine

    工具:小锐云服 PRO ,Windows 命令处理器,Java 环境 系统版本:Windows 10 描述:不知名原因导致的 Java 虚拟机创建失败,百度良久后通过修改系统环境变量,完成了对问题的处理。 提示:若按照教程还是无法完成操作,可以进入右侧的企鹅,找我看看。 视频教程: 文字教程:

    2024年02月12日
    浏览(42)
  • 【Java EE初阶十六】网络原理(一)

            在网络原理中主要学习TCP/IP四层模型中的重点网络协议         应用层是和程序员接触最密切的;         应用程序:在应用层这里,很多时候都是程序员自定义应用层协议(步骤:1、根据需求,明确要传输的信息,2、约定好信息按照什么样的格式来组织)的

    2024年02月20日
    浏览(30)
  • 【Java EE初阶十七】网络原理(二)

    2.2.2 关于可靠传输 4.滑动窗口         前面的三个机制,都是在保证 tcp 的可靠性;         TCP 的可靠传输,是会影响传输的效率的.(多出了一些等待 ack 的时间,单位时间内能传输的数据就少了);         滑动窗口,就让可靠传输对性能的影响,更少一些.TCP 只要引入了可

    2024年02月20日
    浏览(33)
  • 【Java EE 初阶】TCP协议的安全效率机制

    目录 1.应用层协议 2.传输层协议 3.UDP协议格式 4.TCP协议格式 5.TCP的安全效率机制 1.确认应答机制 2.超时重传机制 但是,主机A未收到B发来的确认应答,也可能是因为ACK丢失了; 3.连接管理机制 ​编辑 面试题:会不会有可能变成三次挥手? 面试题:第二个FIN丢包了如何处理?

    2024年02月09日
    浏览(32)
  • 【Java EE初阶三 】线程的状态与安全(下)

             线程安全 : 某个代码,不管它是单个线程执行,还是多个线程执行,都不会产生bug,这个情况就成为“线程安全”。          线程不安全 : 某个代码,它单个线程执行,不会产生bug,但是多个线程执行,就会产生bug,这个情况就成为 “线程不安全”,或者

    2024年02月03日
    浏览(34)
  • 【Java EE初阶六】多线程案例(单例模式)

            单例模式是一种设计模式,设计模式是我们必须要掌握的一个技能;         设计模式是软性的规定,且框架是硬性的规定,这些都是技术大佬已经设计好的;         一般来说设计模式有很多种,且不同的语言会有不同的设计模式,(同时 设计模式也可

    2024年02月03日
    浏览(31)
  • kettle 运行Spoon.bat时,显示错误Could not create the java virtual machine.

    kettle 运行Spoon.bat时,显示错误Could not create the java virtual machine , A fatal exception has occured.Program will exit. 可能原因:jdk版本,运行内存不足  错误原因:并非运行内存不足和jdk版本问题,通过查询SpoonConsole.bat得知 Launching Spoon with console output: D:data-integrationdata-integration\\\"D:data-in

    2024年02月05日
    浏览(63)
  • Unrecognized VM option ‘CMSParallelRemarkEnabled‘ Error: Could not create the Java Virtual Machine.

    演示分布式事务 Seata报:如下异常 Unrecognized VM option ‘CMSParallelRemarkEnabled’ Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit. 错误原因: 1、表明在尝试启动 Seata Server 时遇到了 Java 虚拟机(JVM)配置的问题。具体来说,Unrecognized VM option ‘CM

    2024年04月17日
    浏览(46)
  • 【Java EE初阶二十二】https的简单理解

             当前网络上,主要都是 HTTPS 了,很少能见到 HTTP.实际上 HTTPS 也是基于 HTTP.只不过 HTTPS 在 HTTP 的基础之上, 引入了\\\"加密\\\"机制;引入 HTTPS 防止你的数据被黑客篡改 ;         HTTPS 就是一个重要的保护措施.之所以能够安全, 最关键的在于\\\"加密”;         明文:

    2024年02月22日
    浏览(40)
  • 【Java EE初阶八】多线程案例(计时器模型)

            计时器类似闹钟,有定时的功能,其主要是到时间就会执行某一操作,即可以指定时间,去执行某一逻辑(某一代码)。         在java标准库中,提供了Timer类,Timer类的核心方法是schedule( 里面包含两个参数,一个是要执行的任务代码,一个是设置多久之后

    2024年01月21日
    浏览(39)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包